c++ - 为什么 C++ 编译器可以将函数声明为 constexpr,而不能是 constexpr?

标签 c++ templates c++11 constexpr compile-time

为什么 C++ 编译器可以将函数声明为 constexpr,而不能是 constexpr?

例如: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;
}

输出:

28
28
6
5
2

为什么在这一行出错://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error 甚至对于 C++14 和 C++1z

为什么编译器允许标记reduce()作为constexpr ,但是 reduce()即使所有参数都传递给 reduce() 也不能用作模板参数在编译时已知?


某些编译器的效果相同 - 支持 C++14 -std=c++14 :

对于所有这些情况编译OK,直到未使用行://print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error

最佳答案

Why does the C++ compiler makes it possible to declare a function as constexpr, which can not be constexpr?

事实并非如此。但是您没有定义函数 constexpr。您正在定义一个模板。

让我们设置:

struct Is_constexpr {
  constexpr Is_constexpr() = default;
  constexpr auto bar() {
    return 24;
  }
};

struct Not_constexpr {
  auto bar() {
    return 24;
  }
};

现在,如果您尝试将函数(不是模板)定义为使用 Not_constexpr 的 constexpr,编译器将不允许您:

constexpr auto foo_function(Not_constexpr v)
{
  return v.bar();
  // error: call to non-constexpr function 'auto Not_constexpr::bar()'
}

然而,您正在定义一个模板。让我们看看这是怎么回事:

template <class T>
constexpr auto foo(T v)
{
  return v.bar();
}

编译器允许你这样做。没有错误。为什么?因为它是模板。有些实例化可能是 constexpr,有些不是,具体取决于 T:

int main() {
  constexpr Is_constexpr is_c;
  constexpr Not_constexpr not_c;

  std::integral_constant<int, foo(is_c)> a; // OK
  //std::integral_constant<int, foo(not_c)> a; // ERROR

}

关于c++ - 为什么 C++ 编译器可以将函数声明为 constexpr,而不能是 constexpr?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45092557/

相关文章:

javascript - JS 替换对象中的占位符值

java - 如何将速度模板加载到 EJB 中以用作邮件模板

c++ - 这不能用可变参数模板参数包来完成吗?

c++ - 如何在 C++11 中获取整数线程 ID

c++ - volatile 、std::sig_atomic_t 和 atomic_signal_fence

c++ - 将测试代码构建为库还是可执行文件?

c++ - 避免在此模板代码中创建变量

c++ - 点未声明

c++ - 我可以在 C++ 中使用 ReadDirectoryChangesW() 来观察多个目录的变化吗?

c++ - 编译模板类因 g++ 或 clang++ 失败