Search code examples
c++templatesmetaprogrammingpartialspecialization

Double partial template specialization for a class


I've stumbled upon a little problem with a little code I'm doing while learning c++11/14. Basically I have a Debugging class which I want to handle all the message printing. Most debugging/logging classes have log levels of sorts, but I want to use a flag for each message I have.

For that I have a little enum where I define my flags and their values:

enum DebugFlag {
    Flag1 = 0,
    Flag2 = 1,
    Flag3 = 2
};

Aditionally, I have a Debugging class, which I've managed to specialize for Flag types and it works pretty well.

template<DebugFlag T>
class Debug {
public:
    template <typename U>
    static void print(U &&arg) {}
};

template <>
class Debug<static_cast<DebugFlag>(1)> {
public:
    static void print(std::string &&message) {
        std::cerr<<message<<"\n";
    }

    static void print(std::ostream &message) {
        std::cerr<<DebugStream()().str()<<"\n"; 
        DebugStream()().str(""); 
        DebugStream()().clear();  
    }

    static void print(std::string &message) {
        std::cerr<<message<<"\n";
    }
};

To call this class, I use a call like:

Debug<Flag1>::print("Message\n"); // should not do anything with Flag1 compiled to 0 value
Debug<Flag2>::print("Message\n"); // should work

Now I wanted to expand this class to also take bool values, so calls like this will work:

Debug< Flag2<2 >::print("Message\n"); // should not do anything with Flag1 compiled to 2 value
Debug< Flag2<1 >::print("Message\n"); // should work

The problem is I need a second partial specialization for my Debug class, that is bool, and I can't figure exactly what the syntax is for this. This is the closest I've come to it, but still can't figure out what I'm doing wrong or if it's possible without making a secondary class and changing the way I want my call to look like: http://cpp.sh/6yemn


Solution

  • I don't understand exactly how you want to be able to use your class, but here's something that works.

    template <typename T, T v = T()>
    class Debug {};
    
    template <>
    class Debug<Flag, Flag2> {
    public:
        void f() { std::cout<<"This is good\n"; }
    };
    
    template <>
    class Debug<bool, true> {
    public:
        void f() { std::cout<<"This is good too\n"; }
    };
    

    The problem is that you need to specify the type : whether you want to use a bool or a Flag, and then the value. You can instantiate the class like so :

    Debug<bool, true> trueDebug;
    Debug<Flag, Flag2> flag2Debug;
    

    Other instances won't have the f function unless you add a specialization. For example :

    template <Flag v>
    class Debug<Flag, v> {
    public:
        void f() { std::cout<<"This is bad\n"; }
    };
    

    Live example