为什么C ++编译器可以声明一个函数为constexpr,不能是constexpr? [英] Why does the C++ compiler makes it possible to declare a function as constexpr, which can not be constexpr?
问题描述
为什么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 ] (强调我的):
如果实例化模板特化一个constexpr函数
模板或成员函数类模板将无法满足
对constexpr
function 或constexpr构造函数
专业化仍然是constexpr
函数constexpr
构造函数,即使调用这样的函数不能出现在
a常量表达式 ...
注意:该
从函数模板实例化的函数称为函数
模板专门化; / p>
当它不是模板时,它会失败:
int constexpr reduce(int(* f)(int,int),std :: initializer_list< int& i){
return std :: accumulate(std :: next(il.begin()),il.end(),*(il.begin()),f);
}
编译器现在会抱怨你不能调用非< c> 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:
28
28
6
5
2
Why 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 ofinitializer_list
is constexpr: http://en.cppreference.com/w/cpp/utility/initializer_list/initializer_list
Why 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/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++ - 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++14
For 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:
A constant-expression function may be called with non-constant expressions, in that case there is no requirement that the resulting value be evaluated at compile time.
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):
If the instantiated template specialization of a constexpr function template or member function of a class template would fail to satisfy the requirements for a
constexpr
function or constexpr constructor, that specialization is still aconstexpr
function orconstexpr
constructor, even though a call to such a function cannot appear in a constant expression ...
Note: that
A function instantiated from a function template is called a function template specialization;
When 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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!