Home > Blockchain >  Dealing with inconsistent typedefs in generic code
Dealing with inconsistent typedefs in generic code

Time:03-05

I routinely come across code in large codebases that do not follow the standard convention for typedefs e.g. ThisType instead of this_type.

Writing generic code where I can no longer rely on this_type means I have to provide some scaffolding code for each type that does not have this_type.

I suppose both this_type and ThisType can be defined. However, in a large codebase that adds extra noise and is something that reviews will need to routinely check.

Is there a way to wrap it in a type_trait such that I can write something along the lines of: this_type<SomeType>::value_type OR some other generic solution?

CodePudding user response:

Maybe can be done in a simpler way... anyway, I propose a tag dispatching / SFINAE solution.

First of all, a simple recursive tag struct

template <std::size_t N>
struct tag : public tag<N-1u>
{ };

template <>
struct tag<0u>
{ };

to avoid ambiguities in cases more that one of the possible type names are defined.

Then a template function (only declared) for every type you want extract from the possible types; one for type

template <typename T, std::void_t<typename T::type>* = nullptr>
typename T::type getType (tag<0u>);

one for this_type

template <typename T, std::void_t<typename T::this_type>* = nullptr>
typename T::this_type getType (tag<1u>);

one for ThisType

template <typename T, std::void_t<typename T::ThisType>* = nullptr>
typename T::ThisType getType (tag<2u>);

and one (to be a little silly) for MySillyTypeName

template <typename T, std::void_t<typename T::MySillyTypeName>* = nullptr>
typename T::MySillyTypeName getType (tag<3u>);

Observe that the number of the tag are differents: this avoid the possible ambiguity and give a priority order for the names.

Now a trivial struct that uses getType() to extract the required type

template <typename T, typename U = decltype(getType<T>(tag<100u>()))>
struct GetType { using type = U; };

The following is a full compiling C 17 example

#include <type_traits>

template <std::size_t N>
struct tag : public tag<N-1u>
{ };

template <>
struct tag<0u>
{ };

template <typename T, std::void_t<typename T::type>* = nullptr>
typename T::type getType (tag<0u>);

template <typename T, std::void_t<typename T::this_type>* = nullptr>
typename T::this_type getType (tag<1u>);

template <typename T, std::void_t<typename T::ThisType>* = nullptr>
typename T::ThisType getType (tag<2u>);

template <typename T, std::void_t<typename T::MySillyTypeName>* = nullptr>
typename T::MySillyTypeName getType (tag<3u>);

template <typename T, typename U = decltype(getType<T>(tag<100u>()))>
struct GetType { using type = U; };

struct foo1 { using type = short; };
struct foo2 { using this_type = int; };
struct foo3 { using ThisType = long; };
struct foo4 { using MySillyTypeName = long long; };

int main()
{
  static_assert( std::is_same_v<short,     GetType<foo1>::type> );
  static_assert( std::is_same_v<int,       GetType<foo2>::type> );
  static_assert( std::is_same_v<long,      GetType<foo3>::type> );
  static_assert( std::is_same_v<long long, GetType<foo4>::type> );
}
  • Related