gpt4 book ai didi

c++ - 从 constexpr 模板函数调用非 constexpr

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:26:28 27 4
gpt4 key购买 nike

我偶然发现了调用非 constexpr 函数的 constexpr 模板函数:在以下代码段中,由于调用了非 constexpr setbar 无法按预期编译,但 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 函数。下一个代码片段的 -Og 编译结果显示,constexpr foo 将被优化,而普通的 foo2 则不会,而两者都不会满足 constexpr 函数的要求(可能是 inline constexpr 隐含的结果):

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是一个函数。

要使函数(例如 bar)成为 constexpr,它必须满足所有 constexpr 规则(从一个标准到另一个标准),并且在函数的定义中进行检查。如果不满足这些规则,您会收到错误消息。

对于函数模板,因为您只有一个模板来生成函数,所以您无法强制执行 constexpr 的规则。例如。在您的示例中,您不知道模板定义处是否 set<T>(x)constexpr因为您可能有一些 set 的模板实例化谁是 set 的 constexpr 和一些其他模板实例化哪些不是。所以你不能检查 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]

  1. 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 a constexpr function or constexpr constructor, even though a call to such a function cannot appear in a constant expression. If no specialization of the template would satisfy the requirements for a constexpr function or constexpr constructor when considered as a non-template function or constructor, the template is ill-formed; no diagnostic required.

关于c++ - 从 constexpr 模板函数调用非 constexpr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48541044/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com