首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从constexpr模板函数调用非constexpr

从constexpr模板函数调用非constexpr
EN

Stack Overflow用户
提问于 2018-01-31 11:27:16
回答 1查看 1.6K关注 0票数 8

我无意中发现了调用非compile函数的compile模板函数:在下面的片段栏中,由于调用了非compile集但foo编译,无法按预期进行编译。有人能告诉我foo编译的原因吗?

代码语言:javascript
复制
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);
}

编译器无法使用错误进行编译:

代码语言:javascript
复制
<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不满足而非的要求(可能是因为的内联含义):

代码语言:javascript
复制
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);
}

编译结果:

代码语言:javascript
复制
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
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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的要求,那么这是允许的,但是在一个常量表达式中不允许专门化。

您可以从示例中看到稍微修改过的代码:

代码语言:javascript
复制
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. 如果类模板的constexpr函数模板或成员函数的实例化模板专门化无法满足对constexpr函数或constexpr构造函数的要求,则即使对此类函数的调用不能出现在常量表达式中,该专门化仍然是constexpr函数或constexpr构造函数。如果当模板被视为非模板函数或构造函数时,模板的任何专门化都不能满足对constexpr函数或constexpr构造函数的要求,则模板的格式不正确;不需要诊断。
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48541044

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档