c++macrosmetaprogramming

Can this C++ template be simplified with a C MACRO?


I have a template class with a read() method. It needs to call a C functions: read1(), read2(), read3() etc based upon the template parameter value. Is there is a cleaner way to do this than a switch on the template value? I have tried using a MACRO:

#define READ(N) read##N##()

But this doesn't work as X is simply replaced by the C Preprocessor as 'N' resulting in "readN()"

int read1()
{
}

int read2()
{
}

int read3()
{
}

...

template <int N>
struct Reader
{
    int read()
    {
        switch (N)
        {
        case 1:
            return read1();
        case 2:
            return read2();
        case 3:
            return read3();
        }
    }

    /* Doesn't work as X is simply replaced by the C Preprocessor as 'N' resulting in "readN()"
    #define READ(X) read##X##()
    int read()
    {
        return READ(N);
    }
    */
};



Solution

  • One can

    1. use if constexpr instead of switch to select proper read call:

    2. use constexpr lookup table, for neatness.

    3. use, if desperate, constexpr implementation of map, but standard ISO one is too generic and cannot be constexpr. A map is more useful for run-time dispatching.

    4. wrap functions into specializations of a template function, if there are only few.

    Lookup table as a function pointer table:

    #include <iostream>
    
    int read1(){ return 1; }
    int read2(){ return 2; }
    int read3(){ return 3; }
    
    template <int N>
    struct Reader
    {
        static constexpr int (*read_functions[])(void) = {
          nullptr, 
          read1,
          read2,
          read3,
        };
    
        static_assert(N > 0 && N < std::size(read_functions));
        int read() {
            return read_functions[N]();
        }
    };
    
    int main()
    {
        Reader<3> r;
        std::cout << "Read " << r.read();
    }
    

    See on godbolt. Note, with -O2 it's completely optimized out.