解析C ++构造函数&呼吁歧义

时间:2017-01-20 11:02:56

标签: c++ arrays templates ambiguity

我有一个很好的小型万能交易阵列类型,直到现在都符合我的所有需求。

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()将采用float2Array<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}}然后大多只是使用它。

有什么想法吗?

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。