Home > OS >  How to use `std::is_enum` with unnamed `enum`s?
How to use `std::is_enum` with unnamed `enum`s?

Time:10-20

The title is pretty much self explanatory. Here is my situation:

#include <type_traits>

class C1{
    enum{
        c1 = 3
    }
}

class C2{
    enum{
        c2 = 10
    }
}

template<class C>
class C3{
    void do_this();
    void do_that();

    void foo(){
        if constexpr(std::is_enum<C::c1>::value){
            do_this();
        }
        if constexpr(std::is_enum<C::c2>::value){
            do_that();
        }
    }
}

If I'd try to compile this I'd get the error

error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c1’

error: type/value mismatch at argument 1 in template parameter list for ‘template<class _Tp> struct std::is_enum’
note: expected a type, got ‘typename C::c2’

So hence my question: is it possible to use std::is_enum with unnamed enums?

CodePudding user response:

You can use decltype to get the type associated with c1 and c2 and then use SFINAE as shown below . Demo:

struct C1{
    enum{
        c1 = 3
    };
};

struct C2{
    enum{
        c2 = 10
    };
};

template<class C>
class C3{
    void do_this(){std::cout << "do this called" << std::endl;}
    void do_that(){std::cout << "do that called " << std::endl;}
public:
    //overload for calling do_this
    template<typename T = C, std::enable_if_t<std::is_same_v<T, C1>, bool> = std::is_enum<decltype(T::c1)>::value >void foo()
    {
        do_this();
    }
    //overload for calling do_that
    template<typename T = C, std::enable_if_t<std::is_same_v<T, C2>, bool> = std::is_enum<decltype(T::c2)>::value >void foo()
    {
        do_that();
    }
    //overload when none of the conditions are satisfied
    template<typename... T>
    void foo(T...)
    {
        std::cout <<"pack called " << std::endl;
    }
     
};
int main()
{
    C3<C1> c1;
    c1.foo();     //calls do_this() using #1

    C3<C2> c2;
    c2.foo();     //calls do_that() using #2

    C3<int> c3;
    c3.foo();    //calls the pack version
    
}

This has the advantage that this will work with C 11 also as now you don't need to use if constexpr. C 11 Demo

CodePudding user response:

You should probably name the them both the same thing so the template works with both of them:

#include <cstdio>
#include <type_traits>

struct C1 {
    enum { c = 3 };
};

struct C2 {
    static constexpr int c = 10;
};

template <class C>
void foo() {
    if constexpr (std::is_enum_v<decltype(C::c)>) {
        std::puts("::c is an enum");
    } else {
        std::puts("::c is not an enum");
    }
}

int main() {
    foo<C1>();
    foo<C2>();
}
  • Related