【发布时间】:2020-06-13 18:28:39
【问题描述】:
这个问题的动机是this one。
考虑以下代码:
struct B {};
struct S {
B b; // #1
S() = default;
template <typename ...dummy> // #2
constexpr S(const S&) {}
template <typename ...dummy> // #3
constexpr S(S &other)
: S(const_cast<const S&>(other)) // #4
{}
};
S s;
constexpr S f() {return s;}
int main() {
constexpr auto x = f();
}
GCC 成功编译了这段代码,但 Clang 拒绝了它 (Example on Godbolt.org)。 Clang 产生的错误信息是
<source>:21:20: error: constexpr variable 'x' must be initialized by a constant expression
constexpr auto x = f();
^ ~~~
<source>:13:11: note: read of non-constexpr variable 's' is not allowed in a constant expression
: S(const_cast<const S&>(other))
^
<source>:13:11: note: in call to 'S(s)'
<source>:18:25: note: in call to 'S(s)'
constexpr S f() {return s;}
^
<source>:21:24: note: in call to 'f()'
constexpr auto x = f();
^
<source>:17:3: note: declared here
S s;
^
请注意,如果我们删除 #2、#3 或 #4 中的任何一个,两个编译器都会接受此代码。如果我们用int b = 0;替换#1,both compilers reject it。
我的问题是:
- 根据当前标准,哪个编译器是正确的?
- 如果 GCC 是正确的,为什么用
int b = 0;替换 #1 会使这段代码格式错误?如果 Clang 是正确的,为什么删除 #2、#3 或 #4 中的任何一个会使这段代码格式正确?
【问题讨论】:
-
顺便说一句,这些函数都不是复制构造函数。根据定义,构造函数只有在不是模板时才是复制构造函数。
-
@NicolBolas 感谢您指出这一点。我只在标题中使用“复制构造函数”来总结问题。如果您有更好的标题,请随时编辑。
标签: c++ templates language-lawyer copy-constructor constant-expression