使用聚合初始化程序初始化类的模板(聚合类型)成员,但没有多余的括号

时间:2018-11-10 10:55:16

标签: c++ class templates constructor c++14

具有此代码:

myProperty

在创建myProperty<int> ip{1}; myProperty<Vec3> vp1{{1, 2, 3}}; // myProperty<Vec3> vp2{1, 2, 3}; ERROR: myProperty doesn't have a matching constructor. 类型对象时:

vp2

是否有一种优雅的方法可以使myProperty初始化工作?将Vec3专用于WebSecurityConfigurerAdapter实在是太过分了。

1 个答案:

答案 0 :(得分:6)

一个简单的解决方案是使用可变参数模板构造函数:

template <typename ...P> myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}

它使myProperty<Vec3> vp2{1, 2, 3};得以编译。

它也阻止myProperty<Vec3> vp1{{1, 2, 3}};进行编译(这似乎符合您的意图)。

此选项的问题在于,它会阻止副本构造正常工作。
(如果参数是非常量myProperty<T>左值,则此可变参数构造函数比myProperty(const myProperty &)更好。)

这可以通过SFINAE解决:

带有<experimental/type_traits>的C ++ 17:

#include <experimental/type_traits>
#include <utility>

template <typename T, typename ...P> using list_constructible = decltype(T{std::declval<P>()...});

// ...

template
<
    typename ...P,
    typename = std::enable_if_t<std::experimental::is_detected_v<list_constructible, T, P...>>
>
myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}

C ++ 14:

#include <type_traits>
#include <utility>

template <typename...> using void_t = void;
template <typename DummyVoid, template <typename...> class A, typename ...B> struct is_detected : std::false_type {};
template <template <typename...> class A, typename ...B> struct is_detected<void_t<A<B...>>, A, B...> : std::true_type {};
template <typename T, typename ...P> using list_constructible = decltype(T{std::declval<P>()...});

// ...

template
<
    typename ...P,
    typename = std::enable_if_t<is_detected<void, list_constructible, T, P...>::value>
>
myProperty(P &&... p) : m_value{std::forward<P>(p)...} {}