【问题标题】:My variadic templated constructor hides copy constructor, preventing the class to be copied我的可变参数模板构造函数隐藏了复制构造函数,防止类被复制
【发布时间】:2021-08-31 04:58:03
【问题描述】:

我开设了Vector<numType, numberOfCoords> 课程。我对此很满意,这有点奇怪,但它似乎在一开始就奏效了。但是我发现复制向量是不可能的。

原因是为了让坐标数成为模板,有一个模板化的可变参数构造函数,它需要正确的坐标数。

这就是它的样子,去掉了实用数学方法:

template <typename NumType, unsigned char Size>
class Vector
{
public:
  using CoordType = NumType;

  //Vector(const Vector& v) : values(v.values) {}
  //Vector(Vector&& v) : values(std::move(v.values)) {}

  template<typename... NumTypes>
  constexpr Vector(NumTypes&&... vals) : values{ std::forward<NumTypes>(vals)... }
  {
    static_assert(sizeof...(NumTypes) == Size, "You must provide N arguments.");
  }

  Vector(const std::array<NumType, Size>& values) : values(values) {}
  Vector(std::array<NumType, Size>&& values) : values(std::move(values)) {}

  const NumType& operator[](size_t offset) const { return values[offset]; }
  NumType& operator[](size_t offset) { return values[offset]; }
  //Vector& operator=(const Vector& other) { values = other.values; }
  //Vector& operator=(Vector&& other) { values = std::move(other.values); }

  std::array<NumType, Size> values;

};

如您所见 - 现在已注释掉 - 我确实尝试手动实现复制、移动和分配操作。它没有效果,错误总是沿着:

cannot convert ‘Vector<int, 3>’ to ‘int’ in initialization

这是因为它仍在尝试使用可变参数构造函数,而不是复制构造函数。

这是一个完整的工作示例:https://ideone.com/Jz86vP

【问题讨论】:

    标签: c++ templates c++14 variadic-templates


    【解决方案1】:

    你可能会:

    • SFINAE 你的可变参数构造函数,例如:

      template <typename... NumTypes,
                std::enable_if_t<sizeof...(NumTypes) == Size
                             && std::conjunction<std::is_same<NumType, NumTypes>::value,
                                int> = 0>
      constexpr Vector(NumTypes&&... vals) : values{ std::forward<NumTypes>(vals)... }
      {
      }
      

      注意:std::conjunction 是 C++17,但可以在 C++14 中完成。

    • 或添加标签:

      template <typename... NumTypes>
      constexpr Vector(struct SomeTag, NumTypes&&... vals) :
          values{ std::forward<NumTypes>(vals)... }
      {
      }
      
    • 或重新设计类,例如:

      template <typename T, std::size_t>
      using always_type = T;
      
      template <typename NumType, typename Seq> class VectorImpl;
      
      template <typename NumType, std::size_t ... Is>
      class VectorImpl<NumType, std::index_sequence<Is...>>
      {
      public:
        using CoordType = NumType;
      
        VectorImpl(const VectorImpl&) = default;
        VectorImpl(VectorImpl&&) = default;
        VectorImpl& operator=(const VectorImpl&) = default;
        VectorImpl& operator=(VectorImpl&&) = default;
      
        constexpr VectorImpl(always_type<NumType, Is>... vals) : values{ std::forward<NumType>(vals)... }
        {
        }
      
        VectorImpl(const std::array<NumType, sizeof...(Is)>& values) : values(values) {}
        VectorImpl(std::array<NumType, sizeof...(Is)>&& values) : values(std::move(values)) {}
      
        const NumType& operator[](size_t offset) const { return values[offset]; }
        NumType& operator[](size_t offset) { return values[offset]; }
      
        std::array<NumType, sizeof...(Is)> values;
      };
      
      template <typename T, std::size_t N>
      using Vector = VectorImpl<T, std::make_index_sequence<N>>;
      

      Demo

    【讨论】:

    • 制作可变参数构造函数explicit 可能是一种选择
    • 非常感谢,重新设计看起来真的很棒。但是我能问一下模板的前向声明到底在做什么吗?
    • 另外,我不知道如何在类之外实现方法。
    • 我做部分专业化。所以我需要声明主模板。类外的实现与任何模板(专业化)一样:template &lt;typename NumType, std::size_t ... Is&gt; NumType&amp; VectorImpl&lt;NumType, std::index_sequence&lt;Is...&gt;&gt;::operator[](size_t offset) { return values[offset]; }
    猜你喜欢
    • 2012-12-05
    • 2016-03-22
    • 1970-01-01
    • 2016-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-24
    • 2015-10-06
    相关资源
    最近更新 更多