Reputation: 487
Basically what I want to do is as follows. Let's assume we have a template member function foo:
template <typename T>
T SomeClass::foo();
and somehow a user passed map< string, int > as a template argument:
foo<map<string, int>>();
What I want to do here is, when defining the function foo, to get the inner types, string and int. I tried much guesswork to un-specialize the argument but was of no avail.
template <map<typename K, typename V>>
map<K, V> SomeClass::foo(); // absolutely illegal
I thought about using partial specialization, but it didn't work as foo is a class member function.
Upvotes: 0
Views: 654
Reputation: 888
Here's another possible solution. The method foo dispatches to a foo_detail method that take a pointer to T as a parameter. That parameter is not used in foo_detail. Instead, the parameter allows the overload resolution to select which foo_detail is called.
The solution has a clunky feel because of the unused parameter. Fortunately, this can be hidden in the private portion of SomeClass so that users of SomeClass don't have to know about it.
#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;
}
Upvotes: 0
Reputation: 145259
Off the cuff:
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(); }
Upvotes: 1
Reputation: 93274
If you want a generic way of grabbing inner types from a template, you can use explicit specialization:
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;
};
Usage:
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
>);
If you only care about doing that when calling a function, you can just make the function a template:
template <typename K, typename V>
void foo(std::map<K, V>);
Upvotes: 1