我应该如何处理以下情况:
我正在编写自己的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);
它编译得很好并调用适当的float构造函数。
但是如果我写Vector2 v(3, 4);
它会失败,因为模板化的迭代器构造函数“更适合”并调用Vector2(Iterator(3), Iterator(4))
。
在这种情况下我该怎么做?
我的想法是关于引入assign(It1, It2)
成员方法而不是构造函数,但也许有更好的解决方案?
另外,您如何看待ASSERT(end - begin == 2)
行?我知道这意味着我不能,例如,传递std::list
的迭代器,但带来额外的安全性。我应该这样做吗?
答案 0 :(得分:6)
这样的事似乎有效:
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)
来确定两个迭代器之间的距离。
答案 1 :(得分:1)
我应该如何处理以下情况
我认为您应该通过删除float
构造函数来处理它。从阅读代码开始,我们不清楚你应该从中得到什么样的对象。
通过阅读callsite代码,我没有理由相信vector2 v2(1, 5);
创建了两个向量的向量,每个向量都有一个值。
就个人而言,我原本希望它能创建一个1x5
矩阵。
如果这是您图书馆的常见用例,请考虑使用named constructor:
vector2 Create2x1(float f1, float f2);
re:ASSERT
ASSERT是一个很好的健全性检查,但需要你的Iterator
支持随机访问(或至少减去查找距离)。这可能会过度限制其使用。考虑使用std::distance
或检查local_vector_storage
之后是否为{2}。
答案 2 :(得分:1)
在特定情况下,我认为根本没有介绍Vector2(Iterator begin, Iterator end)
c'tor的感觉。
一般情况下,当std::vector
的维度固定且永不改变时,我认为模仿Vector2
(实质上是数组的包装)是没有意义的。 std::vector
和Vector2
之间的用例重叠可忽略不计:std::vector
通常从另一个容器初始化,而Vector2
则为50/50用两个值或另一个Vector2初始化。
即使你决定继续,行:
ASSERT(end - begin == 2);
会极大地限制构造函数的有用性,因为相对较少的迭代器支持算术。
答案 3 :(得分:1)