Warum ermöglicht es der C ++ - Compiler, eine Funktion als constexpr zu deklarieren, die nicht constexpr sein kann?

Warum ermöglicht es der C ++ - Compiler, eine Funktion als constexpr zu deklarieren, die nicht constexpr sein kann?

Zum Beispiel:http: //melpon.org/wandbox/permlink/AGwniRNRbfmXfj8

#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;
}

Ausgabe

28
28
6
5
2

Warum Fehler in dieser Zeile://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error even für C ++ 14 und C ++ 1z?

std::plus - constexpr T operator()( const T& lhs, const T& rhs ) const; (seit C ++ 14) - constexpr: http: //en.cppreference.com/w/cpp/utility/functional/pluconstexpr initializer_list(); (seit C ++ 14) - Konstrukt voninitializer_list ist constexpr: http: //en.cppreference.com/w/cpp/utility/initializer_list/initializer_lis

Warum erlaubt der Compiler das Markieren vonreduce() wieconstexpr, aberreduce() kann nicht als Vorlagenparameter verwendet werden, auch wenn alle Parameter an @ übergeben wurdreduce() zur Kompilierungszeit bekannt?

Der gleiche Effekt für einige Compiler - dieunterstütztes C ++ 14 -std=c++14:

x86 GCC 7.0.0-std=c++1z -O3: http: //melpon.org/wandbox/permlink/AGwniRNRbfmXfj8 x86 gcc 4.9.2-std=c++14 -O3: https: //godbolt.org/g/wmAaD x86 gcc 6.1-std=c++14 -O3: https: //godbolt.org/g/WjJQE x86 clang 3.5-std=c++14 -O3: https: //godbolt.org/g/DSCpY x86 clang 3.8-std=c++14 -O3: https: //godbolt.org/g/orSrg x86 Visual C ++ - Sie sollten Code kopieren und einfügen in:http: //webcompiler.cloudapp.netARM gcc 4.8.2, ARM64 gcc 4.8, PowerPC gcc 4.8, AVR gcc 4.5.3 - unterstützt nicht C + 14-std=c++14

Für alle diese Fälle kompilieren Sie OK, bis die Zeile nicht mehr verwendet wird://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error

Antworten auf die Frage(6)

Ihre Antwort auf die Frage