1

EDIT: As pointed out by cpplearner, I had to add 'template' after T:: before Key. e.g. : T::template Key<i>::to_string

I'm writing an unroll template to create a compile-time 'for loop' to execute a specified callback for each iteration of the loop.

As for context; I'm writing a keycode helper structure in which I can simply define an enum (C++ sided) variable and its string 'name' value in one macro. This is used to easily setup a to_string method for each key to use later in the application. (Building a JavaScript-sided 'enumeration' object with the enum values at each object key)

The problem however is that my code compiles under MSVC, but doesn't compile under GCC.

I simplified the code to represent the problem here

#include <string>

struct KeyCodes
{
    enum KeyCode { Key1, Key2 };

    typedef void (*LoopCallback)(KeyCode keyCode, std::string str);

    template <KeyCode> struct Key
    {
        std::string to_string(){ return "undefined"; }
        static const bool is_valid = false;
    };
};

template<> struct KeyCodes::Key<KeyCodes::KeyCode::Key1>
{
    std::string to_string() { return "Key1"; };
    static const bool is_valid = true;
};

template<> struct KeyCodes::Key<KeyCodes::KeyCode::Key2>
{
    std::string to_string() { return "Key2"; };
    static const bool is_valid = true;
};

template <typename T, KeyCodes::KeyCode i, bool is_valid, KeyCodes::KeyCode max>
struct KeyCodeLoop {};

template <typename T, KeyCodes::KeyCode i, KeyCodes::KeyCode max>
struct KeyCodeLoop<T, i, true, max>
{
  static void loop(KeyCodes::LoopCallback to_call)
  {
    to_call(i, T::Key<i>::to_string());
    const KeyCodes::KeyCode next = i + 1;
    KeyCodeLoop<T, next, T::Key<next>::is_valid, max>::loop(to_call);
  }
};

If I replace T with the actual "KeyCodes" structure, it does however compile. Like so

#include <string>

struct KeyCodes
{
    enum KeyCode { Key1, Key2 };

    typedef void (*LoopCallback)(KeyCode keyCode, std::string str);

    template <KeyCode> struct Key
    {
        std::string to_string(){ return "undefined"; }
        static const bool is_valid = false;
    };
};

template<> struct KeyCodes::Key<KeyCodes::KeyCode::Key1>
{
    std::string to_string() { return "Key1"; };
    static const bool is_valid = true;
};

template<> struct KeyCodes::Key<KeyCodes::KeyCode::Key2>
{
    std::string to_string() { return "Key2"; };
    static const bool is_valid = true;
};

template <typename T, KeyCodes::KeyCode i, bool is_valid, KeyCodes::KeyCode max>
struct KeyCodeLoop {};

template <typename T, KeyCodes::KeyCode i, KeyCodes::KeyCode max>
struct KeyCodeLoop<T, i, true, max>
{
  static void loop(KeyCodes::LoopCallback to_call)
  {
    to_call(i, KeyCodes::Key<i>::to_string());
    const KeyCodes::KeyCode next = i + 1;
    KeyCodeLoop<T, next, KeyCodes::Key<next>::is_valid, max>::loop(to_call);
  }
};

What could be causing this behaviour, or am I doing something very wrong in general?

0 Answers0