Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplified tuple implementation

Tags:

c++

c++11

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.

like image 540
Allan Avatar asked Mar 23 '23 07:03

Allan


1 Answers

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.

like image 159
Andy Prowl Avatar answered Apr 06 '23 19:04

Andy Prowl