Make C ++ call the correct template method in an ugly way

I am preparing a vector library and am trapped. I want to enable recursive vectors (i.e. vec<H,vec<W,T> > ), so I would like my min and other functions to be recursive as well. Here is what I have:

 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); 

This last call is ugly! How can I name the correct method only with min(v1,v2) ? The best I can think of is to get rid of the "vec" class (so v1 and v2 should be defined as container <2, float, vec_array <2, float →) and add another method template<N,T,VT> min which calls min<N,T,VT,VT>(v1,v2) .

Thanks!

+7
c ++ templates
source share
2 answers
 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); 

What I finally did to make it work.

The ambiguity was that both arguments are of the same type - container<2,float,vec_array<2,float> > . This is one point for the min(const T&,const T&) method min(const T&,const T&) . Since min(const container<N,T,VT1>& v1, const container<N,T,VT2>& v2) is a coincidence and more specialized, it also got an extra point, and the compiler could not decide what to use. Switching the total minimum to using two type arguments - min (const T1 &, const T2 &) - transfers it to the subordination.

I also switched to using the “typedef pattern” instead of inheritance to define vec<N,T> without dealing with the messy tag container<N,T,VT> . This makes vec<N,T>::t exact match with the correct function.

Now when I use typedef instead of inheritance and two types in the common min function instead of one, the correct method is called.

0
source share

You will have an overload resolution that the first min prefers for the first case. It takes both arguments with an exact match, and the second min needs a database conversion to convert the arguments.

As you later understood (through experimentation?), If you use container<...> as argument types, instead of derived classes, conversion with a derived base will no longer be necessary, and then overload resolution will be preferable to the second because otherwise they are both equally good accept arguments, but the second pattern (in your own decision) is more specialized.

However, in your own solution, you need to put typename in front of the return type in order to make a Standard C ++ solution. I think that the problem that forces you to define the second template is that in order to make the template more specialized, the first min min must accept all the arguments that the second template takes, which is calculated by simply comparing the arguments of the second template with first

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

Thus, various types of template parameters are tried to output to the same template parameter, which will cause a conflict and make the first template unsuccessful, displaying all the arguments of the second template. For your own solution, this is not the case:

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

This will force the first template to deduce all types of parameters from the second template, but not vice versa: container<N, T, VT> will not match an arbitrary T Thus, your own solution template is more specialized and called, and then explicitly redirected to another template.

Finally, note that your own decision only accepts containers where the third template argument is the same, while your other min template accepts containers where this argument may be different for both arguments. I'm not sure if this is on purpose, but given another min function that conflicts if you don't make the types of the third argument the same as shown above, I'm not sure how to fix this.


Subsequently, the commentator edited his own answer, so most of my links above to “your own answer” no longer apply.

+1
source share

All Articles