Search code examples
c++g++x-macros

X-macro driven C++ template class instantiation


I am trying to instantiate a templatized class based on an X-macro. However, this is giving me syntax errors error: wrong number of template arguments (0, should be 1). What is the correct way to instantiate a templatized class from an x-macro?

#include <string.h>
#include <iostream>

#define FOO \
  X(, aaa)    \
  X(int, bbb)  \

template <class T> class A
{
  public:
    A(){ std::cout << "Hello From A\n";}
};

class B
{
  public:
    B() {std::cout << "Hello From B\n";}
};

int main()
{
#define X(a,b) \
  if (0 == strlen(#a)) { \
    printf("%s is empty\n", #b); \
    B b; \
  } else { \
    printf("%s is NOT empty\n", #b); \
    A<a> b; \
  }

  FOO
#undef X

  return 0;
}

Solution

  • The issue here isn't that your syntax is wrong, but rather that both branches of the if and else get compiled regardless of whether a is empty or not. The compiler error will trigger because the else branch will try instantiating A<>, which isn't legal.

    To fix this, you could consider adding a level of indirection. Here's a modified piece of code where the type AHelper serves to output something of the proper type.

    /* By default, use A. */
    template <typename... Args> struct AHelper {
        using result = A<Args...>;
    };
    
    /* But not if there are no arguments. */
    template <> struct AHelper<> {
        using result = B;
    };
    
    int main() {
    
    #define X(a,b) \
        AHelper<a>::result b;
    
        FOO
    #undef X
    
    }
    

    (Initially, I thought this would be as easy as using if constexpr rather than if, but in a non-template context the compiler is supposed to evaluate both the if and else branch and the same compiler error results.)