【问题标题】:C++ basic constructor questionC++基本构造函数问题
【发布时间】:2011-03-13 10:12:22
【问题描述】:

我应该如何处理以下情况:

我正在编写自己的 2D 矢量类,并具有以下代码:

class Vector2 : public (...)
public:

   Vector2(float x, float y) {

      local_vector_storage_[0] = x;
      local_vector_storage_[1] = y;
   }

   template <typename Iterator> Vector2(Iterator begin, Iterator end) {

      ASSERT(end - begin == 2);

      resize(2);

      std::copy(begin, end, local_vector_storage_.begin());
   }

// ...
};

现在,如果我说Vector2 v(3.0f, 4.0f);,它可以正常编译并调用适当的浮点构造函数。

但如果我写 Vector2 v(3, 4); 它会失败,因为模板化迭代器构造函数 “更适合”Vector2(Iterator(3), Iterator(4)) 被调用。

在这种情况下我该怎么办?

我的想法是引入 assign(It1, It2) 成员方法而不是构造函数,但也许有更好的解决方案?

编辑:

另外,你觉得ASSERT(end - begin == 2) 线怎么样?我知道这意味着我不能传递 std::list 的迭代器,但会带来额外的安全性。我应该这样做吗?

【问题讨论】:

  • 好问题!我只看到三个选项: 1. 使用范围而不是迭代器; 2.添加显式(int, int)构造函数; 3. 保持原样并要求明确的浮动。您还可以考虑添加独立的工厂函数,例如 make_vector
  • 关于assert 的问题:您可以改用std::distance。或者可能只传递一个迭代器,因为无论如何你总是复制恒定数量的元素。
  • local_vector_storage_的类型是什么?我猜这是一些向量,但向量是什么?类本身不是模板,所以向量的类型可能是固定的吧?顺便提一句。你到底想做什么?
  • 对于您的断言,您可以使用std::distance 而不是减法,因此它适用于所有迭代器类型。

标签: c++ constructor templates vector


【解决方案1】:

这样的事情似乎有效:

template<typename T>
struct notnumeric {typedef int OK;};

template<>
struct notnumeric<int> {};

class Vector2
{
public:
   Vector2(float x, float y)
   {
   }

   template <typename Iterator>
   Vector2(Iterator begin, Iterator end, typename notnumeric<Iterator>::OK dummy = 0)
   {
   }
};

我相信它使用 SFINAE 来防止编译器为非数字类型选择第二个 ctor。

至于ASSERT (end - begin == 2),我认为您应该使用std::distance(begin, end) 来确定两个迭代器之间的距离。

【讨论】:

  • 你可以使用std::enable_if&lt;!std::is_numeric&lt;Iterator&gt;::value, Iterator&gt;::type来改进它。这将删除“虚拟”参数并使用编译器提供的(或 Boost,如果你很绝望)类型特征,这比自定义编写的类型特征更可靠。此外,您可以抛出,而不是使用断言。
  • 同意那更好(如果可行的话),尽管我认为enable_if 只会在 C++0x 之前得到提升。
  • @DeadMG: enable_if 如何删除构造函数上的虚拟对象?我认为这只适用于具有返回类型的方法。
  • @Staffan:Enable_if 适用于可以使用类型声明的任何地方。在这种情况下,论据。人们只是最常使用返回类型。 @Jon Hanson:它也在 TR1 中。
【解决方案2】:

编辑:这是二维向量吗?还是只有两个向量?我为二维向量回答了这个问题。

出现以下情况应该如何处理

我认为您应该通过删除 float 构造函数来处理它。通过阅读代码,不清楚您应该从中期待什么样的对象。

通过阅读调用站点代码,我没有理由相信 vector2 v2(1, 5); 创建了一个由两个向量组成的向量,每个向量都有一个值。

就我个人而言,我希望它会创建一个1x5 矩阵。

如果这是您的库的常见用例,请考虑named constructor

vector2 Create2x1(float f1, float f2);

回复:断言

ASSERT 是一个很好的健全性检查,但需要您的 Iterator 支持随机访问(或至少减法以找到距离)。这可能会过度限制其使用。考虑使用std::distance 或之后检查local_vector_storage 是否为2 号。

【讨论】:

  • 在我看来,vector v2(1, 5) 正在构建一个二维向量,其中一个维度的大小为 1,另一个维度为 5。local_vector_storage 成员保存每个维度的标量值,而不是其他维度向量。 OP 可以更改该名称,但矢量 API 是有意义的(至少对我而言!)
  • @Neil:嗯……现在我完全糊涂了。也许你是对的,但为什么要让尺寸浮动?也许它会编译?将 xy 分配给 local_storage 似乎很奇怪,因为实际存储空间从未调整大小。
【解决方案3】:

在特定情况下,我认为引入 Vector2(Iterator begin, Iterator end) c'tor 毫无意义。

一般来说,当你的Vector2 的维度是固定的并且永远不会改变时,我认为模仿std::vector(它本质上是一个数组的包装器)是没有意义的。 std::vectorVector2 之间的用例重叠可以忽略不计甚至不存在:std::vector 通常从另一个容器初始化,而 Vector2 将使用两个值或另一个 Vector2 初始化 50/50 .

即使你决定继续,这条线:

ASSERT(end - begin == 2);

将极大地限制构造函数的实用性,因为支持算术的迭代器相对较少。

【讨论】:

    【解决方案4】:
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    相关资源
    最近更新 更多