简体   繁体   English

从constexpr模板函数调用non constexpr

[英]Call non constexpr from constexpr template function

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. 我偶然在调用非constexpr功能constexpr模板功能:在下面的代码片段无法编译预期由于非constexpr 设置 ,但FOO编译的号召。 Can anyone tell me the reason why foo compiles? 谁能告诉我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);
}

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

Edit: Appended compiler error and rephrased question. 编辑:附加的编译器错误和重新定义的问题。 Side effects are not in focus here. 这里没有副作用。

As stated by bolov and Rekete1111 below the template will be evaluated later. 如下面的bolov和Rekete1111所述,模板将在稍后进行评估。 When the constexpr restrictions are not met, the constexpr template function becomes some kind of semi constexpr function. 当不满足constexpr限制时,constexpr模板函数成为某种半constexpr函数。 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): 该-oG编译下面的代码片段显示结果,该constexpr foo将被优化掉和公共foo2的不同时兼具履行constexpr功能(可能是一个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);
}

The compile result: 编译结果:

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

It's because foo is a function template and bar is a function. 这是因为foo是一个函数模板, bar是一个函数。

For a function (eg 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. 对于constexpr的函数(例如bar ),它必须满足所有constexpr规则(从标准变为标准)并且在函数的定义中检查。 You get an error if those rules aren't met. 如果不满足这些规则,则会出错。

For a function template because you have only a template to generate functions you can't enforce the rules for constexpr. 对于函数模板,因为您只有一个模板来生成函数,所以您无法强制执行constexpr的规则。 Eg 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. 例如,在模板定义,如果你不知道的点您的示例set<T>(x)constexpr ,因为你可能有一些模板实例set谁是constexpr和其他一些模板实例set哪些不是。 So you can't check that foo meets the requirements for constexpr . 所以你无法检查foo符合constexpr的要求。 You can only check specific instantiations of foo if are constexpr eg foo<int> or foo<char> etc. 你只能检查foo具体实例,如果是constexpr例如foo<int>foo<char>等。

C++ handles this situation by allowing constexpr for a function template indiscriminately (sort of). C ++通过允许constexpr不加选择地使用函数模板来处理这种情况。 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 aa constant expression. 但是,如果模板的实例化不符合constexpr的要求则允许,但是在常量表达式中不允许使用特化。

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. 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. 如果constexpr函数模板的实例化模板特化或类模板的成员函数无法满足constexpr函数或constexpr构造函数的要求,那么该特化仍然是constexpr函数或constexpr构造函数,即使调用这样的函数不能出现在常量表达式中。 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; 如果模板的特化没有满足constexpr函数或constexpr构造函数在被视为非模板函数或构造函数时的要求,则模板格式不正确; no diagnostic required. 无需诊断。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM