我无意中发现了调用非compile函数的compile模板函数:在下面的片段栏中,由于调用了非compile集但foo编译,无法按预期进行编译。有人能告诉我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所述,模板下面的内容将在稍后进行评估。在不满足约束条件的情况下,将模板函数转化为某种半恒函数。下一段代码片段的-Og编译结果显示,将优化and,而普通foo2不满足而非的要求(可能是因为的内联含义):
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发布于 2018-01-31 12:04:54
这是因为foo是一个函数模板,bar是一个函数。
对于一个函数(例如bar)来说,它必须满足所有的规则(从标准到标准),并在函数的定义中进行检查。如果不符合这些规则,就会出错。
对于函数模板,因为您只有一个模板来生成函数,所以不能强制执行constexpr的规则。例如,在模板定义点的示例中,您不知道set<T>(x)是否为constexpr,因为您可能有一些set的模板实例化,后者是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
https://stackoverflow.com/questions/48541044
复制相似问题