【发布时间】:2018-07-10 11:55:32
【问题描述】:
我偶然发现了调用非 constexpr 函数的 constexpr 模板函数: 在以下 sn-p bar 由于调用非 constexpr set 而无法按预期编译,但 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 所述,模板将在稍后进行评估。当不满足 constexpr 限制时,constexpr 模板函数变成某种半 constexpr 函数。下一段代码 sn-p 的 -Og 编译结果显示,constexpr foo 将被优化掉,而普通 foo2 not 而两者都做 not 满足 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
【问题讨论】:
-
“foo 有效”和“bar 失败”是什么意思?它不编译吗?意外行为?
-
由于编译器错误无法编译。我会相应地更新我的问题。
-
模板、构造函数和函数对 constexpr 有不同的规则。在您的示例中, set
(x) 不能使用。只能进行一些持续的评估
标签: c++ templates gcc constexpr c++17