使用static_cast <base />(* this)初始化可变参数CRTP ......:它是合法的吗?

时间:2017-11-26 08:36:54

标签: c++ c++17 crtp static-cast

我有以下示例代码:

#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},
  ... { }

我可以安全地做到这一点,并确保它定义明确吗?

1 个答案:

答案 0 :(得分:3)

从C ++ 17开始,聚合可以具有聚合类型的公共非虚拟基类。 foobar是聚合,因此Foo<foo,bar>是聚合,因此在大括号初始化时会使用聚合初始化

因此,代码在C ++ 17及更高版本中是合法的(它不是之前的代码)。请注意,没有合成“聚合构造函数”,只是大括号初始化对聚合有一个特殊的解释。

BTW,我在这里看不到CRTP(Foo不会继承具有模板参数的模板特化,具体取决于超类型)