我偶然发现constexpr模板函数调用非constexpr函数: 由于非constexpr set 的调用,但 foo 编译,下面的代码片段 bar 无法按预期编译。 谁能告诉我 foo 编译的原因?
template<class T>
void set(T& x){
x++;
}
template<class T>
constexpr void foo(T& x){
set<T>(x);
}
constexpr void bar(int& x){
set<int>(x);
}
void bar(){
int x = 5;
foo(x);
bar(x);
}
编译器无法使用错误进行编译:
<source>: In function 'constexpr void bar(int&)':
<source>:12:13: error: call to non-constexpr function 'void set(T&) [with T = int]'
set<int>(x);
~~~~~~~~^~~
Compiler returned: 1
编辑:附加的编译器错误和改写的问题。这里没有副作用。
如下面的bolov和Rekete1111所述,模板将在稍后进行评估。当不满足constexpr限制时,constexpr模板函数成为某种半constexpr函数。下一个代码片段的-Og编译结果显示,constexpr foo 将被优化,而公共 foo2 不会同时不满足constexpr函数的要求(可能是constexpr的 inline 含义的结果):
template<class T>
void set(volatile T& x){
x++;
}
template<class T>
constexpr void foo(T& x){
set<T>(x);
}
template<class T>
void foo2(T& x){
set<T>(x);
}
void bar(){
int x = 5;
foo(x);
foo2(x);
}
编译结果:
void set<int>(int volatile&):
ldr r3, [r0]
add r3, r3, #1
str r3, [r0]
bx lr
void foo2<int>(int&):
push {r4, lr}
bl void set<int>(int volatile&)
pop {r4, lr}
bx lr
bar():
push {r4, lr}
sub sp, sp, #8
add r4, sp, #8
mov r3, #5
str r3, [r4, #-4]!
mov r0, r4
bl void set<int>(int volatile&)
mov r0, r4
bl void foo2<int>(int&)
add sp, sp, #8
pop {r4, lr}
bx lr
答案 0 :(得分:7)
这是因为foo
是一个功能模板而bar
是一个功能。
对于一个函数(例如bar
)是constexpr,它必须满足所有constexpr规则(从标准变为标准)并且在函数的定义中检查。如果不满足这些规则,则会收到错误。
对于函数模板,因为您只有一个模板来生成函数,所以您无法强制执行constexpr的规则。例如。在您的示例中,在模板定义时,您不知道set<T>(x)
是否为constexpr
,因为您可能有set
的一些模板实例,这些实例是constexpr,而其他模板实例是{ {1}}哪些不是。因此,您无法检查set
是否符合foo
的要求。您只能检查constexpr
的具体实例,如果foo
是constexpr
, foo<int>
或foo<char>
等。
C ++通过允许constexpr
不加选择地使用函数模板来处理这种情况。但是,如果模板的实例化不符合constexpr的要求,则允许,但不允许在常量表达式中使用特化。
您可以通过示例中稍微修改过的代码来看到这一点:
auto set(int a) { return a; }
constexpr auto set(char a) { return a; }
template<class T>
constexpr auto foo(T x){
return set(x);
}
auto test()
{
auto x = foo(24); // foo<int> OK, no error
//constexpr auto cx = foo(24) // foo<int> compiler error
auto y = foo('a'); // foo<char> OK, no erro
constexpr auto y = foo('a'); // foo<char> OK
}
§7.1.5[dcl.constexpr]
- 如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足 constexpr函数或constexpr构造函数的要求, 该专业化仍然是constexpr功能或constexpr 构造函数,即使调用这样的函数也不能出现在 不断表达。如果没有模板的专业化 满足constexpr函数或constexpr的要求 构造函数在被视为非模板函数或构造函数时, 模板格式不正确;无需诊断。
醇>