Reputation: 101
I would like to create a template function that takes as argument, not the template type itself, but a member enum class of the template type. Is this possible?
The following code demonstrates what I want to achieve and I wonder if there is some template magic that can accomplish it for me.
#include <iostream>
using namespace std;
class A{
public:
enum class ID {a1, a2};
static void f(ID id){
switch(id){
case ID::a1:
std::cout << "a1\n";
break;
case ID::a2:
std::cout << "a2\n";
break;
}
}
};
class B{
public:
enum class ID {b1};
static void f(ID id){
switch(id){
case ID::b1:
std::cout << "b1\n";
break;
}
}
};
template<typename TypeName>
void g(TypeName::ID id){
TypeName::f(id);
}
int main(int argc, char **argv){
g(A::ID::a1);
g(A::ID::a2);
g(B::ID::b1);
return 0;
}
With the wanted output being
a1
a2
b1
In particular, note how I want the function g to take TypeName::ID as argument rather than TypeName.
A C++11 solution is preferred, but solutions that work with later versions are also of interest.
Upvotes: 0
Views: 336
Reputation: 217663
template<typename TypeName>
void g(TypeName::ID id){ // WRONG
TypeName::f(id);
}
requires typename
:
template<typename TypeName>
void g(typename TypeName::ID id){
TypeName::f(id);
}
but so, type is not deducible (because of the ::
).
so at call site, you have to specify the type:
g<A>(A::ID::a1);
g<A>(A::ID::a2);
g<B>(B::ID::b1);
As alternative, to keep your expected call site syntax, you might create trait to bind (enum) type to a class:
template <typename E> struct ClassFromId;
template <> struct ClassFromId<A::ID> { using type = A; };
template <> struct ClassFromId<B::ID> { using type = B; };
template<typename E>
void g(E id){
ClassFromId<E>::type::f(id);
}
Upvotes: 2
Reputation: 2038
#include <iostream>
using namespace std;
class A{
public:
enum class ID {a1, a2};
static void f(ID id){
switch(id){
case ID::a1:
std::cout << "a1\n";
break;
case ID::a2:
std::cout << "a2\n";
break;
}
}
};
class B{
public:
enum class ID {b1};
static void f(ID id){
switch(id){
case ID::b1:
std::cout << "b1\n";
break;
}
}
};
template<typename TypeName>
void g(typename TypeName::ID id){
TypeName::f(id);
}
int main(int argc, char **argv){
g<A>(A::ID::a1);
g<A>(A::ID::a2);
g<B>(B::ID::b1);
return 0;
}
Upvotes: 3