本文介绍了为什么C ++编译器可以声明一个函数为constexpr,不能是constexpr?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 为什么C ++编译器可以将一个函数声明为constexpr,它不能是constexpr? 例如: http://melpon.org/wandbox/permlink/AGwniRNRbfmXfj8r #include< iostream> #include< functional> #include< numeric> #include< initializer_list> template< 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函子,类型名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函子,类型名T,类型名... 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<值<< 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 std :: plus - constexpr T operator()(const T& lhs,const T& rhs)const; (自C ++ 14起) - constexpr : http://en.cppreference.com/w/cpp/utility/functional/plus constexpr initializer_list(); (因为C ++ 14) - initializer_list 的构造是 constexpr : http://en.cppreference.com/w/cpp/utility/initializer_list/initializer_list 为什么编译器允许将 reduce()标记为 constexpr ,但 reduce()不能用作模板参数,即使所有参数传递给 reduce()在编译时已知? 对于某些编译器来说效果相同 - 支持C ++ 14 -std = c ++ 14 : x86 GCC 7.0.0 -std = c ++ 1z -O3 : http: //melpon.org/wandbox/permlink/AGwniRNRbfmXfj8r x86 gcc 4.9.2 -std = c ++ 14 -O3 : https://godbolt.org/g/wmAaDT x86 gcc 6.1 -std = c ++ 14 -O3 : https://godbolt.org/g/WjJQE5 x86 clang 3.5 -std = c ++ 14 -O3 : https://godbolt.org/g/DSCpYv x86 clang 3.8 -std = c ++ 14 -O3 : https://godbolt.org/g/orSrgH x86 Visual C ++ - 您应该将代码复制粘贴到: http://webcompiler.cloudapp.net/ ARM gcc 4.8.2,ARM64 gcc 4.8,PowerPC gcc 4.8 ,AVR gcc 4.5.3 - 不支持C + 14 -std = c ++ 14 对于所有这些情况,编译OK,直到未使用的行: // print_constexpr< reduce(std :: plus< int>(),{1,2,3,4,5 ,6,7})>(); //错误 解决方案让我们直接从它的提议, www.open- std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf第4.1节第三段:我引用:查看此问题:一个constexpr函数何时在编译时被求值? template<类型名T> T constexpr reduce(Functor f,std :: initializer_list< T> il){ return std :: accumulate(std :: next(il.begin()),il.end (il.begin()),f); } 同样,如你所知, std :: accumulate 不是 constexpr 函数。 template< int value> void print_constexpr(){std :: cout<值<< std :: endl; } 同样,如你所知,非类型模板参数必须是常量表达式。 现在: 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); } 至于为什么它工作:这里是C ++标准说: / p> [dcl.constexpr / 6 ] (强调我的):注意:该 当它不是模板时,它会失败: int constexpr reduce(int(* f)(int,int),std :: initializer_list< int& i){ return std :: accumulate(std :: next(il.begin()),il.end(),*(il.begin()),f); } 编译器现在会抱怨你不能调用非 constexpr 函数定义为 constexpr Why does the C++ compiler makes it possible to declare a function as constexpr, which can not be constexpr?For example: 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;}Output:2828652Why error at this line: //print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error even for C++14 and C++1z?std::plus - constexpr T operator()( const T& lhs, const T& rhs ) const;(since C++14) - constexpr: http://en.cppreference.com/w/cpp/utility/functional/plusconstexpr initializer_list(); (since C++14) - construcot of initializer_list is constexpr: http://en.cppreference.com/w/cpp/utility/initializer_list/initializer_listWhy does compiler allow to mark reduce() as constexpr, but reduce() can't be used as template parameter even if all parameters passed to reduce() known at compile-time?The same effect for some compilers - which supported C++14 -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++ - you should copy-paste code to: http://webcompiler.cloudapp.net/ARM gcc 4.8.2, ARM64 gcc 4.8, PowerPC gcc 4.8, AVR gcc 4.5.3 - doesn't support C+14 -std=c++14For all these cases compile OK, until unused line: //print_constexpr<reduce(std::plus<int>(), {1, 2, 3, 4, 5, 6, 7})>(); // error 解决方案 Let's go straight from it's proposal,www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf in section 4.1, third paragraph: and I quote:See this question: When does a constexpr function get evaluated at compile time? 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);}Again, as you know, std::accumulate isn't a constexpr function.template<int value>void print_constexpr() { std::cout << value << std::endl; }Again, as you know, non-type template arguments must be constant expressions.Now: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);}As to why it works: Here's what the C++ standard has to say:[dcl.constexpr/6] (emphasis mine):Note: thatWhen its not a template, it will fail:int constexpr reduce(int(*f)(int, int), std::initializer_list<int> il) { return std::accumulate(std::next(il.begin()), il.end(), *(il.begin()), f);}The compiler will complain now that you cannot call a non-constexpr function in a function defined as constexpr 这篇关于为什么C ++编译器可以声明一个函数为constexpr,不能是constexpr?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
05-27 23:55
查看更多