代码之家  ›  专栏  ›  技术社区  ›  Lourens Dijkstra

尝试传递constexpr lambda并使用它显式指定返回类型

  •  2
  • Lourens Dijkstra  · 技术社区  · 7 年前

    我想使用一个函数并传递一个 constexpr lambda . 但是,只有通过推导类型,它才能成功编译 auto -> std::array<event, l()> 似乎失败了(第一次)。为什么会这样?

    template <typename Lambda_T>
    constexpr static auto foo(Lambda_T l) -> std::array<event, l()> {
        return {};
    } // error
    
    template <typename Lambda_T>
    constexpr static auto foo(Lambda_T l) {
        return std::array<event, (l())>{};
    } // OK
    
    template <typename Lambda_T>
    constexpr static auto foo(Lambda_T l) -> decltype(l()) { return {}; }
    // OK
    

    注意,lambda返回一个 size_t .

    在没有调用的情况下发生gcc错误(clang接受):

    prog.cc:9:63: error: template argument 2 is invalid
        9 | constexpr static auto foo(Lambda_T l) -> std::array<event, l()>
          |                                                               ^
    prog.cc:9:63: error: template argument 2 is invalid
    prog.cc:9:63: error: template argument 2 is invalid
    prog.cc:9:63: error: template argument 2 is invalid
    prog.cc:9:42: error: invalid template-id
        9 | constexpr static auto foo(Lambda_T l) -> std::array<event, l()>
          |                                          ^~~
    prog.cc:9:61: error: use of parameter outside function body before '(' token
        9 | constexpr static auto foo(Lambda_T l) -> std::array<event, l()>
      |                                                             ^
    prog.cc:9:23: error: deduced class type 'array' in function return type
        9 | constexpr static auto foo(Lambda_T l) -> std::array<event, l()>
      |                       ^~~
    In file included from prog.cc:4:
    /opt/wandbox/gcc-head/include/c++/9.0.1/array:94:12: note: 
    'template<class _Tp, long unsigned int _Nm> struct std::array' declared here
       94 |     struct array
          |            ^~~~~
    prog.cc: In function 'int main()':
    prog.cc:14:5: error: 'foo' was not declared in this scope
       14 |     foo([]() {return 3; });
          |     ^~~
    
    1 回复  |  直到 7 年前
        1
  •  4
  •   Barry    7 年前

    constexpr函数的参数本身不是constexpr对象,因此不能在常量表达式中使用它们。你的两个例子都回来了 array

    要理解为什么,考虑这个荒谬的例子:

    struct Z { int i; constexpr int operator()() const { return i; }; };
    
    template <int V> struct X { };
    template <typename F> constexpr auto foo(F f) -> X<f()> { return {}; }
    
    constexpr auto a = foo(Z{2});
    constexpr auto b = foo(Z{3});
    

    Z 有一个 constexpr 呼叫接线员,这是格式正确的:

    constexpr auto c = Z{3}();
    static_assert(c == 3);
    

    但是如果允许更早的使用,我们将有两个呼叫 foo<Z> 那就得回去了 不同类型 . 只有当实际值 f 是模板参数。