Попытка передать constexpr лямбда и использовать его для явного указания возвращаемого типа - PullRequest
0 голосов
/ 24 января 2019

Я хотел бы использовать функцию и передать 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

Обратите внимание, что лямбда возвращает 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 Ответ

0 голосов
/ 24 января 2019

Параметры функций constexpr сами по себе не являются объектами constexpr, поэтому их нельзя использовать в константных выражениях.Оба ваших примера, возвращающие array s, плохо сформированы, потому что к ним нет действительного вызова.

Чтобы понять почему, рассмотрим этот бессмысленный пример:

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 было параметром шаблона.

Обратите внимание, что компиляция объявления clang сама по себе не является ошибкой компилятора.Это класс ситуаций, которые плохо сформированы, диагностика не требуется.

...