Consider this code
#include <iostream>
#include <type_traits>
enum Thing {Thing0, Thing1, Thing2, NumThings};
enum Object {Object0, Object1, Object2, NumObjects};
template <Thing> struct ThingValue;
template <> struct ThingValue<Thing0> : std::integral_constant<int, 5> {};
template <> struct ThingValue<Thing1> : std::integral_constant<int, 2> {};
template <> struct ThingValue<Thing2> : std::integral_constant<int, 12> {};
template <Object> struct ObjectValue;
template <> struct ObjectValue<Object0> : std::integral_constant<Thing, Thing2> {};
template <> struct ObjectValue<Object1> : std::integral_constant<Thing, Thing0> {};
template <> struct ObjectValue<Object2> : std::integral_constant<Thing, Thing1> {};
int main() {
std::cout << ThingValue<ObjectValue<Object0>::value>::value << '\n'; // 12
}
I'm trying to define, ComposeValues<T, Value, Pack...>
so that the above in main() can be written as ComposeValues<Object, Object0, ThingValue, ObjectValue>::value
. So then this can be extended to any number of such compositions. Not an absolutely vital thing to do, but I'd figure that it would be a nice little exercise to define such a thing. But I'm having difficulty with the syntax:
template <typename T, T Value, template <typename> class...> struct ComposeValues;
template <typename T, T Value, template <typename> class First, template <typename> class... Rest>
struct ComposeValues<T, Value, First, Rest...> {
static auto value = First<typename ComposeValues<T, Value, Rest...>::value>::value;
};
template <typename T, T Value, template <T> class Last>
struct ComposeValues<T, Value, Last> : std::integral_constant<T, Last<Value>::value> {}; // Won't compile.
Is this even possible what I'm trying to do?
The issue that you are having is that you can't mix template templates which take different non-type arguments. In your example, this means that
ObjectValue
andThingValue
cannot bind totemplate <typename> class...
.A way to fix this is to encode your enums in some type kind of template which can hold both of them indiscriminately. A possible way to do this is just treat the enums as
int
s and let the user worry about passing in reasonable types.First we create wrappers around your current types:
Then we can do something pretty similar to what you originally had:
The only difference from your original use-case is that we need to use our wrappers instead of the original enum traits: