处理通用代码中不一致的 typedef
Dealing with inconsistent typedefs in generic code
我经常在大型代码库中遇到不遵循 typedef 标准约定的代码,例如ThisType
而不是 this_type
.
在我不再依赖 this_type
的地方编写通用代码意味着我必须为没有 this_type
.
的每种类型提供一些脚手架代码
我想 this_type
和 ThisType
都可以定义。但是,在大型代码库中会增加额外的噪音,并且是审查需要定期检查的内容。
有没有办法将它包装在 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> );
}
我经常在大型代码库中遇到不遵循 typedef 标准约定的代码,例如ThisType
而不是 this_type
.
在我不再依赖 this_type
的地方编写通用代码意味着我必须为没有 this_type
.
我想 this_type
和 ThisType
都可以定义。但是,在大型代码库中会增加额外的噪音,并且是审查需要定期检查的内容。
有没有办法将它包装在 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> );
}