使用 static_cast<Base>(*this)... 初始化可变 CRTP...:合法吗?
Initializing variadic CRTP with static_cast<Base>(*this)... : is it legal ?
我有以下示例代码:
#include <iostream>
#include <initializer_list>
struct foo { int x{}; };
struct bar { double y{}; };
template<typename... Base>
struct Foo : Base...
{
constexpr auto init_int(int x) const
{ return Foo<foo, Base...>{foo{x}, static_cast<Base>(*this)...}; }
constexpr auto init_double(double x) const
{ return Foo<bar, Base...>{bar{x}, static_cast<Base>(*this)...}; }
};
int main()
{
constexpr auto f = Foo<>{}.init_double(.5).init_int(1234);
static_assert(f.x == 1234);
static_assert(f.y == 0.5);
}
这似乎适用于最近的 Clang 和 GCC(使用 -std=c++1z),但不适用于 MSVC2017。所以我不确定这是不是合法的 C++:它似乎合成了一个看起来像这样的构造函数:
Foo(Base1 b1, Base2 b2, Base3 b3, ...):
Base1{b1},
Base1{b2},
Base3{b3},
... { }
我可以安全地执行此操作并确保它定义明确吗?
自 C++17 起,聚合可以具有聚合类型的 public 非虚基 类。 foo
和 bar
是聚合,所以 Foo<foo,bar>
是聚合,因此 aggregate-initialization 在大括号初始化时使用
因此,该代码在 C++17 及更高版本中是合法的(之前不是)。注意这里没有合成'aggregate constructor',只是brace-initialization对聚合有特殊的解释。
顺便说一句,我在这里看不到 CRTP(Foo 没有继承自具有取决于超类型的模板参数的模板特化)
我有以下示例代码:
#include <iostream>
#include <initializer_list>
struct foo { int x{}; };
struct bar { double y{}; };
template<typename... Base>
struct Foo : Base...
{
constexpr auto init_int(int x) const
{ return Foo<foo, Base...>{foo{x}, static_cast<Base>(*this)...}; }
constexpr auto init_double(double x) const
{ return Foo<bar, Base...>{bar{x}, static_cast<Base>(*this)...}; }
};
int main()
{
constexpr auto f = Foo<>{}.init_double(.5).init_int(1234);
static_assert(f.x == 1234);
static_assert(f.y == 0.5);
}
这似乎适用于最近的 Clang 和 GCC(使用 -std=c++1z),但不适用于 MSVC2017。所以我不确定这是不是合法的 C++:它似乎合成了一个看起来像这样的构造函数:
Foo(Base1 b1, Base2 b2, Base3 b3, ...):
Base1{b1},
Base1{b2},
Base3{b3},
... { }
我可以安全地执行此操作并确保它定义明确吗?
自 C++17 起,聚合可以具有聚合类型的 public 非虚基 类。 foo
和 bar
是聚合,所以 Foo<foo,bar>
是聚合,因此 aggregate-initialization 在大括号初始化时使用
因此,该代码在 C++17 及更高版本中是合法的(之前不是)。注意这里没有合成'aggregate constructor',只是brace-initialization对聚合有特殊的解释。
顺便说一句,我在这里看不到 CRTP(Foo 没有继承自具有取决于超类型的模板参数的模板特化)