简体   繁体   中英

Member enum class of template type as function argument

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.

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

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM