有这个代码:

struct Vec3 {
    int x;
    int y;
    int z;
};

template <typename T>
class myProperty {
public:
   myProperty(const T& initValue) : m_value{initValue} {}
private:
    T m_value;
};

创建 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 是一种矫枉过正。

最佳答案

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

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 解决:

C++17 与 <experimental/type_traits> :
#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)...} {}

关于c++ - 使用聚合初始化器初始化类的模板(聚合类型)成员,但没有额外的括号,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53238233/

10-10 19:49