问题描述
假设我有一个由引擎参数化的 struct
模板 S
:
Suppose I have a struct
template S
that is parametrized by an engine:
template<class Engine> struct S;
我有两个引擎:一个带有 constexpr的静态引擎
成员函数 size()
,以及一个带有非 constexpr
成员函数的动态变量 size()
:
I have two engines: a "static" one with a constexpr
member function size()
, and a "dynamic" one with a non-constexpr
member function 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;
};
我想定义 size()
成员 S
中的函数,如果引擎的 size()可以用作
constexpr
code>是 constexpr
。我写道:
I want to define
size()
member function in S
that can be used as a constexpr
if the engine's size()
is constexpr
. I write:
template<class Engine>
struct S {
constexpr std::size_t size() const {
return engine_.size();
}
Engine engine_;
};
然后使用GCC,Clang,MSVC和ICC编译以下代码:
Then the following code compiles with GCC, Clang, MSVC and ICC:
S<Static_engine> sta; // not constexpr
S<Dynamic_engine> dyn;
constexpr auto size_sta = sta.size();
const auto size_dyn = dyn.size();
考虑到
constexpr
的复杂性格式错误,不需要诊断,我仍然有一个问题:此代码格式正确吗?
Taking into account intricacies of
constexpr
and various "ill-formed, no diagnostic is required", I still have the question: is this code well-formed?
(我用和这两种标准的有效性不同。)
(I tagged this question with both c++17 and c++20 in case this code has different validity in these two standards.)
推荐答案
代码写得很好。
如果constexpr
函数模板的实例化模板特化类模板的成员函数将无法使
满足constexpr函数或constexpr
构造函数的要求,即,专业化仍然是constexpr函数或
constexpr构造函数,即使对此类调用函数
不能出现在常量表达式中。如果模板
的任何专业化都不能满足constexpr函数或constexpr
构造函数的要求,则认为它们是非模板函数或构造函数,则
模板格式错误,不需要诊断
6 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. 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, no diagnostic required.
对于使用
Dynamic_engine ,但是如上一段所述,这不会使
S :: size
格式错误。我们也远离格式错误的NDR领土,因为有效的实例 是可能的。 Static_engine
是一个很好的例子。
The member may not appear in a constant expression for the specialization that uses
Dynamic_engine
, but as the paragraph above details, that does not make S::size
ill-formed. We are also far from ill-formed NDR territory, since valid instantations are possible. Static_engine
being a prime example.
引号来自最新的C ++ 17标准草案n4659,以及类似的措词出现在最新的C ++ 20草案中。
The quote is from n4659, the last C++17 standard draft, and similar wording appears in the latest C++20 draft.
对于
sta的评估.size()
作为常量表达式,在我找不到评估本身不允许的任何内容。因此,它是一个有效的常量表达式(因为该列表告诉我们无效无效)。通常,为了使 constexpr
函数有效,只需要存在 some 个参数集,就可以为其生成有效的常量表达式。如以下示例表格中的标准所示:
As for the evaluation of
sta.size()
as a constant expression, going over the list at [expr.const] I cannot find anything that is disallowed in the evaluation itself. It is therefore a valid constant expression (because the list tells us what isn't valid). And in general for a constexpr
function to be valid, there just needs to exist some set of arguments for which the evaluation produces a valid constant expression. As the following example form the standard illustrates:
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
};
这篇关于Constexpr成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!