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?