从constexpr模板函数调用非constexpr [英] Call non constexpr from constexpr template function

查看:94
本文介绍了从constexpr模板函数调用非constexpr的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我偶然发现了调用非constexpr函数的constexpr模板函数:在以下代码段中,由于调用了非constexpr set bar 无法按预期进行编译,但是 foo 进行了编译.谁能告诉我 foo 编译的原因吗?

I stumbled on constexpr template functions calling non constexpr functions: In the following snippet bar fails to compile as expected due to the call of non constexpr set but foo compiles. Can anyone tell me the reason why foo compiles?

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);
}

编译器无法编译并显示错误:

The compiler fails to compile with the error:

<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

附加的编译器错误和措辞不一的问题.副作用不在这里.

Appended compiler error and rephrased question. Side effects are not in focus here.

如bolov和Rekete1111所述,下面将对模板进行评估.当不满足constexpr限制时,constexpr模板函数将变为某种半constexpr函数.下一个代码片段的-Og编译结果显示,将优化constexpr foo ,而常见的 foo2 则不会,而两者都执行 not 满足constexpr函数的要求(可能是constexpr的 inline 含义的结果):

As stated by bolov and Rekete1111 below the template will be evaluated later. When the constexpr restrictions are not met, the constexpr template function becomes some kind of semi constexpr function. The -Og compile result of the next code snippet shows, that the constexpr foo will be optimized out and the common foo2 not while both do not fulfill the requirements of constexpr functions (probably a consequence of the inline implication of 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 是一个函数.

It's because foo is a function template and bar is a function.

要使一个函数(例如 bar )成为constexpr,它必须满足所有constexpr规则(从标准到标准的变化),并在该函数的定义中进行检查.如果不遵守这些规则,则会出现错误.

For a function (e.g. bar) to be constexpr it must meet all of the constexpr rules (which change from standard to standard) and that is checked at the definition of the function. You get an error if those rules aren't met.

对于函数模板,因为只有一个模板来生成函数,所以无法为constexpr强制执行规则.例如.在您的示例中,在模板定义时,您不知道 set< T>(x)是否为 constexpr ,因为您可能会有一些模板实例化set 是constexpr,而其他一些模板实例化的 set 则不是.因此,您无法检查 foo 是否满足 constexpr 的要求.如果是 constexpr 例如,您只能检查 foo 的特定实例. foo< int> foo< char>

For a function template because you have only a template to generate functions you can't enforce the rules for constexpr. E.g. in your example at the point of the template definition you don't know if set<T>(x) is constexpr because you might have some template instantiations of set who are constexpr and some other template instantiations for set which are not. So you can't check that foo meets the requirements for constexpr. You can only check specific instantiations of foo if are constexpr e.g. foo<int> or foo<char> etc.

C ++通过不加选择地(某种)允许 constexpr 用于功能模板来处理这种情况.但是,如果模板的实例化不满足constexpr的要求,则允许这样做,但不允许在常量表达式中进行专门化.

C++ handles this situation by allowing constexpr for a function template indiscriminately (sort of). However if a instantiations of the template doesn't meet the requirements for constexpr then that is allowed, but the specialization is not allowed in a a constant expression.

您可以在示例中稍作修改的代码来查看此内容:

You can see this with a slightly modified code from your example:

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]

§7.1.5 [dcl.constexpr]

  1. 如果constexpr函数模板或类模板的成员函数的实例化模板特化将无法满足constexpr函数或constexpr构造函数的要求,那个专业化仍然是constexpr函数或constexpr构造函数,即使对此类函数的调用不能出现在常数表达式.如果没有模板的专业化,满足constexpr函数或constexpr的要求构造函数,当被视为非模板函数或构造函数时,模板格式错误;无需诊断.

这篇关于从constexpr模板函数调用非constexpr的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆