处理通用代码中不一致的 typedef

Dealing with inconsistent typedefs in generic code

我经常在大型代码库中遇到不遵循 typedef 标准约定的代码,例如ThisType 而不是 this_type.

在我不再依赖 this_type 的地方编写通用代码意味着我必须为没有 this_type.

的每种类型提供一些脚手架代码

我想 this_typeThisType 都可以定义。但是,在大型代码库中会增加额外的噪音,并且是审查需要定期检查的内容。

有没有办法将它包装在 type_trait 中,这样我就可以按照以下方式写一些东西:this_type<SomeType>::value_type 一些其他通用解决方案?

也许可以用更简单的方式来完成...无论如何,我提出一个标签调度/SFINAE 解决方案。

首先,一个简单的递归tag结构

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

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

为了避免在定义了多个可能类型名称的情况下出现歧义。

然后为您想要从可能类型中提取的每种类型创建一个模板函数(仅声明);一个 type

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

一个用于 this_type

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

一个用于 ThisType

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

还有一个(有点傻)MySillyTypeName

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

注意 tag 的编号是不同的:这避免了可能的歧义,并给出了名称的优先顺序。

现在是一个简单的结构,它使用 getType() 来提取所需的类型

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

下面是完整编译C++17的例子

#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> );
}