特化一个class时,如何取不同数量的模板参数?

When specializing a class, how can I take a different number of template parameters?

我刚问了这个问题: and Yakk - Adam Nevraumont的答案有代码:

template<class T>
struct get_memfun_class;

template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
    using type=T;
};

这些显然是初始声明,然后是 struct get_memfun_class 的特化。但我发现自己不确定:特化可以有不同数量的模板参数吗?

例如,这样的事情合法吗?

template<typename T>
void foo(const T&);

template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);

是否没有要求特化必须采用相同数量的参数?

Are there no requirements that specializations must take the same number of parameters?

有;并对您的示例感到满意。

写的时候

template<class T>
struct get_memfun_class;

你说 get_mumfun_class 是一个模板 struct,只有一个模板 typename 参数;当你写

template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
    using type=T;
};

您定义了一个接收单个模板类型名参数的特化,格式为 R(T::*)(Args...)

从单一类型 R(T::*)(Args...),您可以推断出多个模板参数(RT 和可变参数 Args...,在此示例中)但是类型 R(T::*)(Args...)(接收可变参数列表的 class 的方法)保持为一个。

For example, is something like this legal?

template<typename T>
void foo(const T&);

template<typename K, typename V>
void foo<pair<K, V>>(const pair<K, V>&);

不,但是(如评论中所写)第二个不是 class/struct 部分特化(其中 std::pair<K, V> 保持单一类型),这是合法的;这是一个被禁止的模板 function 偏特化。

但是你可以完全专门化一个模板函数;所以这是合法的(例如)

 template<>
 void foo<std::pair<long, std::string>(const std::pair<long, std::string>&);

get_memfun_class 的完全专业化是合法的(再举一个例子)

template<>
struct get_memfun_class<std::pair<long, std::string>> {
    using type=long long;
};

您似乎混淆了显式特化的模板参数和用于特化模板的模板实参。

template<class T> // one argument
struct get_memfun_class; // get_memfun_class takes one template (type) argument

template<class R, class T, class...Args>
struct get_memfun_class<R(T::*)(Args...)> {
//                      ^^^^^^^^^^^^^^^^
//                      one type argument
    using type=T;
}; // explicit specialization takes one template argument

是的,显式特化有三个模板参数,但这并不意味着显式特化需要三个参数。他们在那里被推导。您可以使用多个类型参数形成一个类型,这就是那里发生的事情。还要考虑您可以完全专门化一个模板:

template <>
struct get_memfun_class<void>;
//                      ^^^^
//                    one type argument

这里也是一样。是的,显式特化不带任何参数,但这仅意味着要推导 none,实际上您正在显式编写模板参数 (void),因此特化的模板参数数量与主模板匹配。

您的示例无效,因为您不能部分特化函数。