I'm working on a platform which does not ahve any standard libraries, and I'm trying to implement a "tuple-like" type.
I only need the facilities to get-by-type, but I would like the compiler to
issue a static_assert if the type does not exist. There are no need asserting
on duplicated types, but it would be nice...
Here is what I have tried:
template<class... Args> struct SimpleTuple;
template<> struct SimpleTuple<> {
    SimpleTuple() { }
};
template<class Head, class... Tail>
struct SimpleTuple<Head, Tail...> {
    typedef Head    HeadType;
    typedef SimpleTuple<Tail...> VATailType;
    SimpleTuple(Head head, Tail... tail) : data(head), rest(tail...) { }
    // Does not compile, because explicit specialization in non-namespace
    // scope is not allowed
    template<typename T> T& get() {
        return rest.get<T>();
    }
    template<> Head& get() {
        return data;
    }
    Head data;
    VATailType rest;
};
I know why it is failing, but I do not know how to avoid this limitation.
I'm looking for an as-simple-as-possible implementation of this.
You could use SFINAE to make only one of the two overloads participate to overload resolution, based on whether or not the type T is the same as Head:
#include <type_traits> // For std::enable_if and std::is_same
template<typename T, 
    typename std::enable_if<!std::is_same<T, Head>::value>::type* = nullptr>
T& get() {
    return rest.get<T>();
}
template<typename T, 
    typename std::enable_if<std::is_same<T, Head>::value>::type* = nullptr>
Head& get() {
    return data;
}
Both std::enable_if and std::is_same can be easily implemented in case you cannot use the ones from the standard library. For instance:
template<typename T, typename U>
struct is_same { static constexpr bool value = false; };
template<typename T>
struct is_same<T, T> { static constexpr bool value = true; };
template<bool C, typename T = void>
struct enable_if { };
template<typename T>
struct enable_if<true, T> { using type = T; };
Here is a live example.
For what concerns the static assertion, you can define a simple trait that checks whether a given type is present in a given tuple type (this trait could have also been defined in terms of std::conditional, which is also trivial to implement):
template<typename...> struct SimpleTuple;
template<typename T, typename U>
struct has_type { static constexpr bool value = false; };
template<typename T, typename U, typename... Ts>
struct has_type<T, SimpleTuple<U, Ts...>> 
{ 
    static constexpr bool value = has_type<T, SimpleTuple<Ts...>>::value; 
};
template<typename T, typename... Ts>
struct has_type<T, SimpleTuple<T, Ts...>> 
{ 
    static constexpr bool value = true; 
};
template<typename T>
struct has_type<T, SimpleTuple<>> 
{ 
    static constexpr bool value = false; 
};
And then use it like so:
template<typename T, 
    typename enable_if<!is_same<T, Head>::value>::type* = nullptr>
T& get() {
    static_assert(has_type<T, SimpleTuple>::value, "Type not found!");
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^    
    return rest.get<T>();
}
Here is a live example that uses the above static_assert().
If you also want to test whether a tuple contains a certain type only once, you could use the following trait, which is a trivial modification of the has_type trait above:
template<typename...> struct SimpleTuple;
template<typename T, typename U>
struct has_unique_type { static constexpr bool value = false; };
template<typename T, typename U, typename... Ts>
struct has_unique_type<T, SimpleTuple<U, Ts...>> 
{ 
    static constexpr bool value = has_unique_type<T, SimpleTuple<Ts...>>::value; 
};
template<typename T, typename... Ts>
struct has_unique_type<T, SimpleTuple<T, Ts...>> 
{ 
    static constexpr bool value = 
        !has_unique_type<T, SimpleTuple<Ts...>>::value; 
};
template<typename T>
struct has_unique_type<T, SimpleTuple<>> 
{ 
    static constexpr bool value = false; 
};
And use it like so:
template<typename T, 
    typename enable_if<!is_same<T, Head>::value>::type* = nullptr>
T& get() {
    static_assert(has_unique_type<T, SimpleTuple>::value, 
        "Type not found or not unique!");
    return rest.get<T>();
}
Here is a live example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With