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