【问题标题】:Variadic user defined conversion/constructor可变用户定义的转换/构造函数
【发布时间】:2016-02-08 02:05:22
【问题描述】:

给定以下使用 std::array 的向量类(用于 2d、3d 或 4d 向量数学),是否可以定义可变参数构造函数和/或转换构造函数?

作为后续问题,这种事情是不好的做法吗?我发现自己需要大量转换整数、浮点数和双精度数。

我知道会发生隐式转换,但我的编译器会对此发出警告(我一般不想关闭它们)。

#include <array>

template<typename T0, size_t S>
class Vec
{
public:

    static_assert(S > 1 && S < 5, "vector dimension must be between 2 and 4");
    static_assert(std::is_arithmetic<T0>::value, "type must be arithmetic");

    std::array<T0, S> v;

    Vec() = default;

    template<class T1, class T2>
    Vec(T1 t1, T2 t2) : v({ static_cast<T0>(t1), 
                            static_cast<T0>(t2) }) {}

    template<class T1, class T2, class T3>
    Vec(T1 t1, T2 t2, T3 t3) : v({ static_cast<T0>(t1), 
                                   static_cast<T0>(t2), 
                                   static_cast<T0>(t3) }) {}

    template<class T1, class T2, class T3, class T4>
    Vec(T1 t1, T2 t2, T3 t3, T4 t4) : v({ static_cast<T0>(t1), 
                                          static_cast<T0>(t2), 
                                          static_cast<T0>(t3), 
                                          static_cast<T0>(t4) }) {}
};

int main(void)
{
    auto foo1 = Vec<float, 2>(1, 2);
    auto foo2 = Vec<float, 2>(1.0f, 2.0f);
    auto foo3 = Vec<float, 2>(1.0, 2.0);
    auto foo4 = Vec<float, 2>(1u, 2u);

    return 0;
}

【问题讨论】:

  • 您关于模板参数 S 的静态断言似乎很奇怪。如果它必须大于 1 且小于 3,那么你也可以说它必须是 2。
  • 谢谢。修复。 2、3 或 4。

标签: c++ templates c++11 constructor type-conversion


【解决方案1】:

当然可以。

顺便说一句,在这种情况下,您不需要默认构造函数,因为这个可变参数构造函数甚至更好,它会将您的数组归零...

template<typename T0, size_t S>
class Vec
{
public:

    static_assert(S > 1 && S < 3, "vector dimension must be between 2 and 4");
    static_assert(std::is_arithmetic<T0>::value, "type must be arithmetic");

    std::array<T0, S> v;

    template <typename ...T>
    Vec(T&& ...a) : v{{ static_cast<T0>(std::forward<T>(a))...}} 
    {}
};

【讨论】:

  • 哦,这很聪明。谢谢你。我想我需要升级:“错误 C2797: 'Vec::v': 成员初始化器列表中的列表初始化或未实现非静态数据成员初始化器”
  • 请注意对于 VS 2013 的任何人,这会编译 "Vec(T1&& ...a) : v({ static_cast(a)... }) {}"
【解决方案2】:

从您的示例中,在我看来,提交的值在任何情况下都具有相同的类型。那么,为什么不使用std::initializer_list?此外,在将它们传递给内部std::array 之前,您将它们转换为T0 类型,所以也许这是值得的。实际上,您并不关心参数的类型,只要您可以将它们转换为 T0

【讨论】:

  • 它们通常具有相同的类型,但有时它们不会。
  • 知道了。从示例中不清楚。无论如何,您实际上对它们的类​​型并不感兴趣,这是一个事实。你不能利用这个吗?您收到的所有回复都在利用这一事实,不是吗?
  • 说实话不是最重要的。
  • 好的。事实上,要么问题不是很清楚,要么我误解了它。对不起。 :-)
【解决方案3】:

如果给类模板添加索引序列:

template<typename T0, size_t S, typename = std::make_index_sequence<S>>
class Vec;

您可以使用这个额外的东西来定义两个构造函数:

template<typename T0, size_t S, size_t... Idx>
class Vec<T0, S, std::index_sequence<Idx...>>
{
    template <size_t> using ith_T = T0;

    ...

    Vec(ith_T<Idx>... ts)
    : v({ts...}) // no cast necessary, they're already T0
    { }

    template <typename U,
              typename = std::enable_if_t<std::is_convertible<U, T0>::value>
              >
    Vec(const Vec<U, S>& rhs)
    : v({static_cast<T0>(rhs.v[Idx])...})
    { }

    ...
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-15
    • 2012-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多