以下代码试图根据成员函数指针类型的返回类型对类模板“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;
}
error C2752: 'special' : more than one partial specialization matches the template argument list
同样的代码被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> {};
最佳答案
这是一个错误。
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,这两个函数模板的偏序是通过在一个函数模板的参数列表中为每个类型模板参数替换发明类型并尝试在另一个函数模板中使用该参数列表进行模板参数推导来确定的。
// 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())
推论显然永远不会成功,因为 void
和 ty6
不统一。
因此函数模板 3 比函数模板 4 更特化。类模板特化 1 比类模板特化 2 更特化。所以尽管 special<void(s::*)()>
匹配两个特化,它明确地实例化特化 1。
关于c++ - 在成员函数返回类型上参数化的类模板部分特化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5110529/