非专业化的C ++模板参数

时间:2018-08-03 13:01:36

标签: c++ templates

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

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

以及用户以某种方式通过 map <字符串,int> 作为模板参数:

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

在定义函数 foo 时,我想做的是获取内部类型 string int 。我尝试了许多猜测工作以使该论据非专业化,但无济于事。

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

我曾考虑过使用部分专业化,但由于 foo 是类成员函数,因此无法使用。

3 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

袖套:

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

答案 2 :(得分:0)

这是另一种可能的解决方案。方法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;
}