Constexpr成员函数

Evg*_*Evg 4 c++ constexpr c++17 c++20

假设我有一个由引擎参数化的struct模板S

template<class Engine> struct S;
Run Code Online (Sandbox Code Playgroud)

我有两个引擎:具有constexpr成员函数的“静态”引擎size()和具有非constexpr成员函数的“动态” 引擎size()

struct Static_engine {
    static constexpr std::size_t size() {
        return 11;
    }
};

struct Dynamic_engine {
    std::size_t size() const {
        return size_;
    }
    std::size_t size_ = 22;
};
Run Code Online (Sandbox Code Playgroud)

我想定义size()的成员函数S可以被用作constexpr如果发动机是size()constexpr。我写:

template<class Engine>
struct S {
    constexpr std::size_t size() const {
        return engine_.size();
    }
    Engine engine_;
};
Run Code Online (Sandbox Code Playgroud)

然后,以下代码将与GCC,Clang,MSVC和ICC一起编译:

S<Static_engine> sta;         // not constexpr
S<Dynamic_engine> dyn;

constexpr auto size_sta = sta.size();
const auto size_dyn = dyn.size();
Run Code Online (Sandbox Code Playgroud)

考虑到constexpr各种复杂性以及“格式错误,无需诊断”,我仍然有一个问题:此代码格式正确吗?

Godbolt.org上的完整代码

(我用标记了这个问题,以防此代码在这两个标准中具有不同的有效性。)

Sto*_*ica 5

代码写的很好。

[dcl.constexpr]

6如果constexpr函数模板或类模板的成员函数的实例化模板特化将无法满足constexpr函数或constexpr构造函数的要求,则即使调用此类函数,该特化仍是constexpr函数或constexpr构造函数。函数不能出现在常量表达式中。如果在将模板视为非模板函数或构造函数时,如果模板的特殊化都无法满足constexpr函数或constexpr构造函数的要求,则模板格式错误,无需诊断。

对于使用的专业化,该成员可能不会出现在常量表达式中Dynamic_engine,但是正如上面的详细说明,该段落不会S::size格式错误。我们也远离格式错误的NDR领域,因为可以进行有效的实例化Static_engine是一个很好的例子。

引用来自最新的C ++ 17标准草案n4659,最新的C ++ 20草案中出现了类似的措辞。


至于sta.size()作为常量表达式的求值,请遍历[expr.const]的列表,我找不到求值本身不允许的任何内容。因此,它是一个有效的常量表达式(因为名单告诉我们什么是不是有效)。通常,要使一个constexpr函数有效,就只需要存在一些参数集,就可以为该参数集生成一个有效的常数表达式。如以下示例表格所示,该标准说明了:

constexpr int f(bool b)
  { return b ? throw 0 : 0; }           // OK
constexpr int f() { return f(true); }   // ill-formed, no diagnostic required

struct B {
  constexpr B(int x) : i(0) { }         // x is unused
  int i;
};

int global;

struct D : B {
  constexpr D() : B(global) { }         // ill-formed, no diagnostic required
                                        // lvalue-to-rvalue conversion on non-constant global
};
Run Code Online (Sandbox Code Playgroud)