1

I have an enum value as a member of a class which I want to pass as a template argument? The compiler complains that the member can not be used in a constant expression. Is there any magic to get this work?

My current solution is a switch-case statement, but in my original code EType has nearly 200 entries. So my initial idea was to write a type_traits for mapping the enum values to types.

Here is an examples (also on ideone.com) for my problem (the problem is the last line in main()):

#include <iostream>

enum EType
{
    eType_A,
    eType_B,
    eType_C
};

struct Foo
{
    Foo(EType eType)
        : m_eType(eType)
    {
    }

    EType m_eType;
};

template <EType eType>
struct Bar
{
    static std::string const toString()
    {
        return "-";
    }
};

template <>
struct Bar<eType_A>
{
    static std::string const toString()
    {
        return "A";
    }
};

template <>
struct Bar<eType_B>
{
    static std::string const toString()
    {
        return "B";
    }
};

int main(int argc, char *argv[])
{
    std::cout << "Bar<eType_A>::toString()=" << Bar<eType_A>::toString() << "\n";
    std::cout << "Bar<eType_B>::toString()=" << Bar<eType_B>::toString() << "\n";
    std::cout << "Bar<eType_C>::toString()=" << Bar<eType_C>::toString() << "\n";

    Foo stFooA(eType_A);
    std::cout << "Bar<stFooA.m_eType>::toString()=" << Bar<stFooA.m_eType>::toString() << "\n"; // <--- here ist the problem
}

The examples generates these errors:

prog.cpp: In function ‘int main(int, char**)’:
prog.cpp:54: error: ‘stFooA’ cannot appear in a constant-expression
prog.cpp:54: error: `.' cannot appear in a constant-expression
prog.cpp:54: error: template argument 1 is invalid

2 Answers 2

5

Template arguments you pass into Bar must be known at compile-time. You're getting that error because stFooA.m_eType can change during run-time so that won't work.

To answer your other question, is there some magic to getting this to work? Perhaps maybe -- are you allowed to make the value of m_eType known at compile-time? If that's a valid constraint for your problem you can change it to something like this and it'll work:

// ...
template <EType eType>
struct Foo
{
    Foo()
    {
    }

    static const EType m_eType = eType;
};

int main(int argc, char *argv[])
{
    std::cout << "Bar<eType_A>::toString()=" << Bar<eType_A>::toString() << "\n";
    std::cout << "Bar<eType_B>::toString()=" << Bar<eType_B>::toString() << "\n";
    std::cout << "Bar<eType_C>::toString()=" << Bar<eType_C>::toString() << "\n";

    Foo<eType_A> stFooA;
    std::cout << "Bar<stFooA.m_eType>::toString()=" 
              << Bar<Foo<eType_A>::m_eType>::toString() 
              << "\n"; // Foo<eType_A>::m_eType is known at compile-time so this works
}
Sign up to request clarification or add additional context in comments.

2 Comments

Good point, but there is no way to make m_eType known at compile-time.
@Lars in that case then you have no choice -- templates probably isn't the right tool for the task and you'll have to resolve it during run-time somehow. Perhaps turn the template argument into a regular function parameter for toString?
3

No, the template expansion is done at compile time. It only works if the value is known when the program is compiled.

The compiler also asks for a constant expression.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.