在成员函数返回类型上参数化的类模板部分特化

时间:2011-02-24 21:12:32

标签: c++ templates visual-c++ member-function-pointers partial-specialization

以下代码尝试根据成员函数指针类型的返回类型专门化类模板'special',导致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;
}
  

错误C2752:'special':多个部分特化匹配模板参数列表

GCC-4.3.4接受相同的代码,如下所示:http://ideone.com/ekWGg
这是VC9中的一个错误,如果是这样,这个错误是否一直存在于VC10中?

然而,我提出了一个可怕的侵入式解决方法(对于这个特定的用例,至少。欢迎更一般的解决方案):

#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> {};

1 个答案:

答案 0 :(得分:3)

这是一个错误。

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

根据14.5.4.2,这两个类模板特化的部分排序与这些虚函数模板的部分排序相同:

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

根据14.5.5.2,这两个函数模板的部分排序是通过在一个参数列表中用每个类型模板参数替换发明类型并在另一个函数模板中使用该参数列表尝试模板参数推导来确定的。 / p>

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

模板参数推导的细节见14.8.2。有效扣除额来自template_name<dependent_type>dependent_type1 (dependent_type2::*)(arg_list)。因此f4(arg3())扣除成功,推断f4<void,ty5>(arg3());f3(arg4())扣除显然永远不会成功,因为voidty6不统一。

因此,函数模板3比函数模板4更专业。而类模板特化1比类模板特化2更专业。因此虽然special<void(s::*)()>匹配两个特化,但它明确地实例化了特化1。