使用 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 非虚基 类。 foobar 是聚合,所以 Foo<foo,bar> 是聚合,因此 aggregate-initialization 在大括号初始化时使用

因此,该代码在 C++17 及更高版本中是合法的(之前不是)。注意这里没有合成'aggregate constructor',只是brace-initialization对聚合有特殊的解释。

顺便说一句,我在这里看不到 CRTP(Foo 没有继承自具有取决于超类型的模板参数的模板特化)