Search code examples
c++stringtemplatesc++11template-meta-programming

Concatenate compile-time strings in a template at compile time?


Currently I have:

template <typename T> struct typename_struct<T*> {
    static char const* name() { 
        return (std::string(typename_struct<T>::name()) + "*").c_str(); 
    }
};

I wonder if I can avoid the whole bit where I'm forced to allocate a string to perform the concatenation.

This is all happening at compile time, i.e. I intend to get the string "int****" when I reference typename_struct<int****>::name(). (Do assume that I have declared a corresponding specialization for int which returns "int")

As the code is written now, does the compiler do the concatenation with std::string during compile time only? (I would be okay with that) Or does such a call result in 4 std::string based concatenations at runtime? (I would not be okay with that)


Solution

  • You could use something like this. Everything happens at compile time. Specialize base_typename_struct to define your primitive types.

    template <const char* str, int len, char... suffix>
    struct append {
      static constexpr const char* value() {
        return append<str, len-1, str[len-1], suffix...>::value();
      }
    };
    
    template <const char* str, char... suffix>
    struct append<str, 0, suffix...> {
      static const char value_str[];
      static constexpr const char* value() {
        return value_str;
      }
    };
    
    template <const char* str, char... suffix>
    const char append<str, 0, suffix...>::value_str[] = { suffix..., 0 };
    
    
    template <typename T>
    struct base_typename_struct;
    
    template <>
    struct base_typename_struct<int> {
      static constexpr const char name[] = "int";    
    };
    
    
    template <typename T, char... suffix>
    struct typename_struct {
      typedef base_typename_struct<T> base;
      static const char* name() {
        return append<base::name, sizeof(base::name)-1, suffix...>::value();
      }
    };
    
    template <typename T, char... suffix>
    struct typename_struct<T*, suffix...>:
      public typename_struct<T, '*', suffix...> {
    };
    
    
    int main() {
      cout << typename_struct<int****>::name() << endl;
    }