¿Por qué el compilador de C ++ hace posible declarar una función como constexpr, que no puede ser constexpr?

¿Por qué el compilador de C ++ hace posible declarar una función como constexpr, que no puede ser constexpr?

Por ejemplo:http://melpon.org/wandbox/permlink/AGwniRNRbfmXfj8r

#include <iostream>
#include <functional>
#include <numeric>
#include <initializer_list>

template<typename Functor, typename T, size_t N>
T constexpr reduce(Functor f, T(&arr)[N]) {
  return std::accumulate(std::next(std::begin(arr)), std::end(arr), *(std::begin(arr)), f);
}

template<typename Functor, typename T>
T constexpr reduce(Functor f, std::initializer_list<T> il) {
  return std::accumulate(std::next(il.begin()), il.end(), *(il.begin()), f);
}

template<typename Functor, typename T, typename... Ts>
T constexpr reduce(Functor f, T t1, Ts... ts) {
  return f(t1, reduce(f, std::initializer_list<T>({ts...})));
}

int constexpr constexpr_func() { return 2; }

template<int value>
void print_constexpr() { std::cout << value << std::endl; }

int main() {
  std::cout << reduce(std::plus<int>(), 1, 2, 3, 4, 5, 6, 7) << std::endl;  // 28
  std::cout << reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7}) << std::endl;// 28

  const int input[3] = {1, 2, 3};   // 6
  std::cout << reduce(std::plus<int>(), input) << std::endl;

  print_constexpr<5>(); // OK
  print_constexpr<constexpr_func()>();  // OK
  //print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error 

  return 0;
}

Salida:

28
28
6
5
2

Por qué error en esta línea://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error incluso para C ++ 14 y C ++ 1z?

std::plus - constexpr T operator()( const T& lhs, const T& rhs ) const; (desde C ++ 14) -constexpr: http://en.cppreference.com/w/cpp/utility/functional/plusconstexpr initializer_list(); (desde C ++ 14) - construcot deinitializer_list esconstexpr: http://en.cppreference.com/w/cpp/utility/initializer_list/initializer_list

¿Por qué el compilador permite marcarreduce() comoconstexpr, peroreduce() no se puede usar como parámetro de plantilla incluso si todos los parámetros pasaron areduce() conocido en tiempo de compilación?

El mismo efecto para algunos compiladores, queC ++ 14 compatible -std=c++14:

x86 GCC 7.0.0-std=c++1z -O3: http://melpon.org/wandbox/permlink/AGwniRNRbfmXfj8rx86 gcc 4.9.2-std=c++14 -O3: https://godbolt.org/g/wmAaDTx86 gcc 6.1-std=c++14 -O3: https://godbolt.org/g/WjJQE5x86 clang 3.5-std=c++14 -O3: https://godbolt.org/g/DSCpYvx86 clang 3.8-std=c++14 -O3: https://godbolt.org/g/orSrgHx86 Visual C ++: debe copiar y pegar el código en:http://webcompiler.cloudapp.net/ARM gcc 4.8.2, ARM64 gcc 4.8, PowerPC gcc 4.8, AVR gcc 4.5.3 - no es compatible con C + 14-std=c++14

Para todos estos casos, compile OK, hasta la línea no utilizada://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error

Respuestas a la pregunta(3)

Su respuesta a la pregunta