I would like to use a function and pass a constexpr lambda
. However, it only compiles successfully if I let the type be deduced through auto
. Explicitly giving the type through -> std::array<event, l()>
seems to fail (the first instance). Why is this?
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
Note that, the lambda returns a size_t
.
gcc errors on this without a call (clang accepts it):
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; });
| ^~~
Parameters to constexpr functions are not themselves constexpr objects - so you cannot use them in constant expressions. Both of your examples returning array
s are ill-formed because there is no valid call to them.
To understand why, consider this nonsense example:
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
has a constexpr
call operator, and this is well-formed:
constexpr auto c = Z{3}();
static_assert(c == 3);
But if the earlier usage were allowed, we'd have two calls to foo<Z>
that would have to return different types. This could only fly if the actual value f
were the template parameter.
Note that clang compiling the declaration is not, in of itself, a compiler error. This is a class of situations that are ill-formed, no diagnostic required.
来源:https://stackoverflow.com/questions/54353463/trying-to-pass-a-constexpr-lambda-and-use-it-to-explicitly-specify-returning-typ