我有一个很好的小型万能交易阵列类型,直到现在都符合我的所有需求。
template <typename T>
class Array
{
...
public:
int Data; // custom value
virtual void InitData() { Data = 0; }
Array(const Array& array);
template <typename U, typename = std::enable_if<std::is_same<U, T>::value, U>> Array(const Array<U>& array);
template <typename... Ts> Array(const Ts&... items);
void Add(const T& item);
template <typename... Ts> void Add(const T& item, const Ts&... rest);
void Add(const Array& array);
}
template <typename... Ts> Array(const Ts&... items);
让我Array<T> array = { ... }
,并分配和返回{...}
初始化列表。因为没有一个构造函数是明确的,所以它非常方便,但也是我现在被卡住的原因。
我希望能够为数组添加任何“合理的”。我现在的主要用例是:
using Curve = Array<float2>;
class Poly : public Array<float2> { using Array::Array; void InitData() override { Data = 1; } };
class Curve2 : public Array<float2> { using Array::Array; void InitData() override { Data = 2; } };
class Curve3 : public Array<float2> { using Array::Array; void InitData() override { Data = 3; } };
上面std::is_same<>
的内容特别是能够将所有曲线视为相同但不相同:不同程度的曲线类型,一切都很好地“静态输入”,所以我所做的一切像DrawCurve(const Curve&)
这样的函数检查学位,然后采取适当的行动。 Curve
是Array的一个很好的别名,而Curve2等是学位专业化。它非常好用。
当我进入曲线构造时,我通常会有一个曲线对象,我在其中添加点或曲线段。所以我希望能够做到:
Curve3 curve;
curve.Add(float2()); // ambiguity
curve.Add(Array<float2>());
不幸的是,当我调用add时,我会在这里产生歧义,因为Add()将采用float2
或Array<float2>
,这可以正常工作,但是Array具有隐式构造函数{{1 },可以将template <typename... Ts> Array(const Ts&...)
作为参数。所以歧义介于
float2
我尝试过制作明确显示数组的构造函数,比如
Array::Add(float2()); // and
Array::Add(Array<float2>(float2()));
但是后来我从Curve3到float2等出现了新的转换错误,它变得一团糟。
我希望在模板或其他C ++好东西的某个地方存在一个简单的解决方案,这正是我所需要的。 (是的,我知道我可以重命名方法:: AddItem()和:: AddArray(),问题将在一秒钟内结束,但我不想这样,因为最终我想用{加倍{ {1}}然后大多只是使用它。
有什么想法吗?
答案 0 :(得分:3)
观察您想要
template <typename... Ts> Array(const Ts&... items);
仅在参数包包含至少一个项目时使用,并且该项目的类型不是Array
模板实例。如果参数包为空,这将成为默认构造函数,所以让我们分别处理这种情况。如果需要,继续显式定义默认构造函数,并让它执行它需要做的事情;现在我们可以从这个用例中消除这种可能性,并开拓进取。
完全避免了这种情况,你想要做的就是只有当它有一个参数时才使用这个构造函数:
template <typename T1, typename... Ts> Array(const T1 &t1, const Ts&... items);
除了它使用的现有参数包之外,您还必须修改此构造函数以使用显式t1
。这应该很简单,但这还不够。仍有歧义。您希望仅在T1不是Array
的情况下选择此构造函数。
可能有办法想出一些令人费解的东西并将其填充到单个std::enable_if
中,并将其推入此模板中。但为了清晰和简单,我会使用辅助类:
template<typename T> class is_not_array : public std::true_type {};
template<typename T>
class is_not_array<Array<T>> : public std::false_type {};
然后在此构造函数的模板中添加一个简单的std::enable_if
,以便仅在第一个模板参数不是Array
时使用SFINAE选择此构造函数,类似于您使用{{1}的方式已经,在另一个构造函数中。
这应解决所有歧义。然后,在此助手类的帮助下,应仅使用至少一个不是std::enable_if
的模板参数来选择此构造函数。当它是Array
时,这个构造函数将不可解析,并且这种情况将转到另一个构造函数。
我还建议在模板中使用通用引用,而不是Array
s。