让C ++以一种不丑的方式调用正确的模板方法

时间:2010-09-08 03:16:13

标签: c++ templates

我正在烹饪一个矢量库并且遇到了障碍。我想允许递归向量(即vec<H,vec<W,T> >)所以我希望我的“min”和其他函数也是递归的。这就是我所拥有的:

template<typename T>
inline T min(const T& k1, const T& k2) {
 return k1 < k2 ? k1 : k2;
}
template<int N, typename T, typename VT1, typename VT2>
inline vec<N,T> min(const container<N,T,VT1>& v1, const container<N,T,VT2>& v2) {
 vec<N,T> new_vec;
 for (int i = 0; i < N; i++) new_vec[i] = min(v1[i], v2[i]);
 return new_vec;
}

...

template<int N, typename T>
class vec : public container<N,T,vec_array<N,T> > {

...

// This calls the first (wrong) method and says you can't call ? on a vec
vec<2,float> v1,v2;
min(v1,v2);
// This says the call is ambiguous
container<2,float,vec_array<2,float> > c1,c2;
min(c1,c2);
// This one actually works
vec<2,float> v3; container<N,T,some_other_type> v4;
min(v3,v4);
// This works too
min<2,float,vec_array<2,float>,vec_array<2,float> >(v1, v2);

最后一次电话很难看!如何使用min(v1,v2)调用正确的方法?我能想到的最好的是摆脱“vec”类(因此v1和v2必须被定义为容器&lt; 2,float,vec_array&lt; 2,float&gt;&gt;)并再添加一个{{1} } min方法调用template<N,T,VT>

谢谢!

2 个答案:

答案 0 :(得分:1)

对于第一种情况,您将拥有更喜欢第一个min的重载决策。它通过完全匹配接受两个参数,而第二个min需要派生到基本转换以接受参数。

正如您随后想出的那样(通过实验?),如果您使用container<...>作为参数类型而不是派生类,则不再需要派生到基本转换,然后重载解析将更喜欢第二个模板,因为否则两者都同样接受参数,但第二个模板(在您自己的解决方案中)更专业。

然而,在您自己的解决方案中,您需要在返回类型之前放置typename以制作解决方案标准C ++。我认为导致您需要定义第二个模板的问题是,为了使模板更加专业化,第一个min min需要接受第二个模板接受的所有参数,这是由只是试图将第二个模板的参数与第一个

匹配
container<N, T, VT1> -> T // func param 1
container<N, T, VT2> -> T // func param 2

因此,不同的模板参数类型尝试推导到相同的模板参数,这将导致冲突并使第一个模板不能成功推导出第二个模板的所有参数。对于您自己的解决方案,情况并非如此:

container<N, T, VT> -> T // func param 1
container<N, T, VT> -> T // func param 2

这将使第一个模板推断出第二个模板中的所有参数类型,但不是相反:container<N, T, VT>将不匹配任意T。因此,您自己的解决方案的模板更加专业化并被调用,然后显式转发到其他模板。

最后请注意,您自己的解决方案只接受第三个模板参数相同的容器,而另一个min模板接受容器,其中两个函数参数的参数可以不同。我不确定这是否是故意的 - 但如果你不会使第三个参数类型与上面所示相同,那么如果其他min函数存在冲突,我不知道如何解决这个问题。


发件人随后编辑了他自己的答案,因此我上面提到的“你自己的答案”的大部分内容都不适用了。

答案 1 :(得分:0)

template<typename T1, **typename T2**>
inline T1 min(const T1& k1, **const T2&** k2) {
    return k1 < k2 ? k1 : k2;
}

...

template<int N, typename T>
struct vec { 
    typedef container<N,T,vec_array<N,T> > t;
};


...

vec<2,float>::t v1,v2;
min(v1,v2);

这就是我最终为了让它发挥作用而做的事情。

歧义是因为两个参数都具有相同的类型 - container<2,float,vec_array<2,float> >。这是min(const T&,const T&)方法的一点。由于min(const container<N,T,VT1>& v1, const container<N,T,VT2>& v2)是一个匹配且更专业,它也有一个额外的点,编译器无法决定使用哪一个。将泛型min切换为使用两个类型参数 - min(const T1&amp;,const T2&amp;) - 将其转换为提交。

我也转而使用“template typedef”而不是继承来定义vec<N,T>,而不必处理凌乱的container<N,T,VT>内容。这使vec<N,T>::t与正确的函数完全匹配。

既然我在一般的min函数中使用了typedef而不是继承和两种类型而不只是一种,那么正在调用正确的方法。