Vit*_*meo 24 c++ language-lawyer constant-expression constexpr c++11
请考虑以下代码段:
template <bool> struct B { };
template <typename T>
constexpr bool pred(T t) { return true; }
template <typename T>
auto f(T t) -> decltype(B<pred(t)>{})
{
}
Run Code Online (Sandbox Code Playgroud)
clang ++ (trunk)编译代码
g ++ (trunk)编译失败,出现以下错误:
src:7:34: error: template argument 1 is invalid
auto f(T t) -> decltype(B<pred(t)>{})
^
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:34: error: template argument 1 is invalid
src:7:25: error: invalid template-id
auto f(T t) -> decltype(B<pred(t)>{})
^
src:7:36: error: class template argument deduction failed:
auto f(T t) -> decltype(B<pred(t)>{})
^
src:7:36: error: no matching function for call to 'B()'
src:1:24: note: candidate: 'template<bool <anonymous> > B()-> B<<anonymous> >'
template <bool> struct B { };
^
src:1:24: note: template argument deduction/substitution failed:
src:7:36: note: couldn't deduce template parameter '<anonymous>'
auto f(T t) -> decltype(B<pred(t)>{})
^
Run Code Online (Sandbox Code Playgroud)
尽管g ++的诊断具有误导性,但我认为这里的问题t不是一个常量表达式.将代码更改为...
decltype(B<pred(T{})>{})
Run Code Online (Sandbox Code Playgroud)
... 在godbolt.org上的g ++:live示例中修复了编译错误
什么编译器在这里表现正常?
海湾合作委员会是错误的。没有规则阻止以这种方式在常量表达式中使用函数的参数。
However, you cannot use the value of the parameter in such a context, and the set of types T for which f is callable is quite restricted. To see why, we need to consider what constructs will be evaluated when evaluating the expression pred(t):
// parameters renamed for clarity
template <typename U>
constexpr bool pred(U u) { return true; }
template <typename T>
auto f(T t) -> decltype(B<pred(t)>{});
Run Code Online (Sandbox Code Playgroud)
The evaluation semantics for the call pred(t) are as follows:
pred's parameter u from f's parameter tpred, which trivially creates a bool value trueuSo, f is only callable for types T for which the above only involves constructs that are valid during constant evaluation (see [expr.const]p2 for the rules). The requirements are:
T must be a literal typeu from t must be a constant expression, and in particular, must not perform an lvalue-to-rvalue conversion on any member of t (because their values are not known), and must not name any reference member of tIn practice, this means that f is callable if T is an empty class type with a defaulted copy constructor, or if T is a class type whose copy constructor is constexpr and does not read any members of its argument, or (strangely) if T is std::nullptr_t (although clang currently gets the nullptr_t case wrong).
| 归档时间: |
|
| 查看次数: |
478 次 |
| 最近记录: |