Classification of a class template parameterized by the type of member function

The following code, which attempts to specialize the template for the "special" class, based on the returned type type of member function pointer types, results in a compilation error with VC9:

template<class F> struct special {}; template<class C> struct special<void(C::*)()> {}; template<class R, class C> struct special<R(C::*)()> {}; struct s {}; int main() { special<void(s::*)()> instance; return 0; } 

error C2752: 'special': more than one partial specialization corresponds to a list of template arguments

The same code is accepted by GCC-4.3.4, as shown in the image: http://ideone.com/ekWGg
Is this an error in VC9, and if so, is this error stored in VC10?

However, I came up with a terrifying obsessive workaround (at least for this particular use case).

 #include <boost/function_types/result_type.hpp> #include <boost/type_traits/is_same.hpp> template<typename F, typename R> struct is_result_same : boost::is_same< typename boost::function_types::result_type<F>::type, R > {}; template<class F, bool = is_result_same<F, void>::value> struct special {}; template<class R, class C> struct special<R(C::*)(), true> {}; template<class R, class C> struct special<R(C::*)(), false> {}; 
+6
c ++ visual-c ++ templates member-function-pointers partial-specialization
source share
1 answer

This is mistake.

 template <class C> struct special<void(C::*)()>; // specialization 1 template <class R, class C> struct special<R(C::*)()>; // specialization 2 

According to 14.5.4.2, the partial ordering of these two patterns of patterns coincides with the partial ordering of these patterns of an imaginary function:

 template <class C> void f(special<void(C::*)()>); // func-template 3 template <class R, class C> void f(special<R(C::*)()>); // func-template 4 

In accordance with clause 14.5.5.2, the partial ordering of these two function templates is determined by substituting the invented types for each parameter of the type template in the list of arguments of one and trying to output the argument of the template using this list of arguments in another function template.

 // Rewrite the function templates with different names - // template argument deduction does not involve overload resolution. template <class C> void f3(special<void(C::*)()>); template <class R, class C> void f4(special<R(C::*)()>); struct ty5 {}; struct ty6 {}; struct ty7 {}; typedef special<void(ty5::*)()> arg3; typedef special<ty6 (ty7::*)()> arg4; // compiler internally tests whether these are well-formed and // the resulting parameter conversion sequences are "exact": f3(arg4()); f4(arg3()); 

Information about the output of the template argument is given in 14.8.2. Valid findings include template_name<dependent_type> and dependent_type1 (dependent_type2::*)(arg_list) . Thus, the output of f4(arg3()) succeeds by f4<void,ty5>(arg3()); . The output of f3(arg4()) will obviously never succeed, since void and ty6 not combined.

Therefore, the template of function 3 is more specialized than the template of function 4. And the specialization of template 1 is more specialized than the specialization of template 2. Therefore, although special<void(s::*)()> corresponds to both specializations, it uniquely creates an instance of specialization 1 .

+3
source share

All Articles