2017-09-08 103 views
3

下面的代码编译失败:Constexpr成员函数

// template<class> 
struct S { 
    int g() const { 
     return 0; 
    } 

    constexpr int f() const { 
     return g(); 
    } 
}; 

int main() 
{ 
    S /*<int>*/ s; 
    auto z = s.f(); 
} 

GCC,例如,抱怨:错误:调用非constexpr函数 '的int ::克()const的' 。这是完全合理的。但如果我将S放入模板中,代码将编译(使用MSVC 15.3,GCC 7.1.0,clang 4.0.1进行检查)。

为什么? constexpr在类模板中有什么特殊含义?

据我了解,这段代码是不正确的,但标准并不要求编译器产生错误(为什么?)。

+0

一方面,有趣的行为。另一方面,为什么从constexpr函数中调用一个非constexpr函数呢? – AndyG

+0

@AndyG这只是一个简单的例子。在我的情况下,'S'是一个模板类,根据模板参数从不同的基类派生。 'g()'在基类中。然后我做了''()''constexpr',并且只在_some_基类('constexpr'ness有意义)中创建了'g()''constexpr'。当'S'由非'constexpr'' g()'派生的基类时,我感到困惑,因此没有发现编译器错误。因此,这个问题。 – Evgeny

+1

最好是,因为我们希望能够拥有一个模板类,这个模板类可能是constexpr的方法,这取决于它的模板参数,也可能不是。我不知道这个标准在哪里是允许的。 – Yakk

回答

1

每[dcl.constexpr]

The definition of a constexpr function shall satisfy the following constraints:
...
every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be one of those allowed in a constant expression

g()到的呼叫中不允许一常量表达式。每[expr.const]:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression...:
— an invocation of a function other than [...] a constexpr function

它看起来像一些编译器可能允许你这样做,你在做什么,因为z未声明constexpr因此该值不需要在被称为编译时。如果你改变你的代码

constexpr auto z = s.f(); 

你会看到所有这些编译器将进行BARF,模板或没有。

+0

零甚至可以用'getchar()'来代替。 – Evgeny

+0

来自[cppreference.com](http://en.cppreference.com/w/cpp/language/constexpr):_A'constexpr'函数必须满足以下要求:...至少存在一组参数值,使得函数的调用可以是核心常量表达式的一个评估子表达式(对于构造函数,在常量初始化器中使用就足够了)(自C++ 14以来)。违反此项目要求不需要诊断。问题是,为什么不需要诊断? – Evgeny

+0

@Evgeny:很好地捕捉到无需诊断的方面。通常的解释是,执行某些事情要么花费太多时间,要么不可能为所有输入做。 – AndyG