取消专门化C++模板参数

Un-specializing C++ template parameter

本文关键字:参数 C++ 专门化 取消      更新时间:2023-10-16

基本上我想做的事情如下。假设我们有一个模板成员函数foo:

template <typename T>
T SomeClass::foo();

并且不知何故,用户通过了map<string,int>作为模板参数:

foo<map<string, int>>();

这里我想做的是,在定义函数foo时,获取内部类型,stringint。我试了很多猜测来解释这个论点,但都无济于事。

template <map<typename K, typename V>>
map<K, V> SomeClass::foo();  // absolutely illegal

我曾想过使用部分专门化,但它没有起作用,因为foo是一个类成员函数。

如果您想要从模板中获取内部类型的通用方法,可以使用显式专门化:

template <typename T>
struct unpack;
template <template <typename...> class C, typename A, typename B>
struct unpack<C<A, B>>
{
using first  = A;
using second = B;
};

用法:

static_assert(std::is_same_v<string,
typename unpack<map<string, int>>::first
>);
static_assert(std::is_same_v<int,
typename unpack<map<string, int>>::second
>);

如果你只关心在调用函数时这样做,你可以把函数做成一个模板:

template <typename K, typename V>
void foo(std::map<K, V>);

即兴:

template< class T >
struct Foo
{
static auto impl() -> T;
};
template< class K, class V >
struct Foo< map< K, V > >
{
static auto impl() -> map< K, V >;
};
template< class T >
auto foo()
-> T
{ return Foo<T>::impl(); }

这里有另一个可能的解决方案。方法foo分派给一个foo_detail方法,该方法将指向T的指针作为参数。foo_detail中未使用该参数。相反,该参数允许重载解析选择调用哪个foo_detail。

由于未使用的参数,该解决方案有一种笨拙的感觉。幸运的是,这可以隐藏在SomeClass的私有部分,这样SomeClass用户就不必知道它了

#include <map>
#include <iostream>
#include <string>
#include <typeinfo>
using std::map;
using std::cout;
using std::endl;
using std::string;
class SomeClass
{
public:
template <typename T>
T foo()
{
return foo_detail((T *)0);
}
private:    
template<typename T>
T foo_detail(T *)
{
cout << "foo called with type " << typeid(T).name() << endl;
return T();
}
template <typename K, typename V>
map<K, V> foo_detail(map<K, V> *)
{
cout << "foo map specialization called with types "
<< typeid(K).name() << ' ' << typeid(V).name() << endl;
return map<K,V>();
}
};
int main()
{
SomeClass s;
s.foo<double>();
s.foo<map<int, string> >();
return 0;
}