通过继承避免在 类 之间重复 typedef
Avoid repetition of typedefs between classes with inheritance
我正在我的一个库中创建一个面向元编程的小型模块,它使用 List<Ts...>
class 进行编译类型列表操作。
我用空参数包专门化 List
以专门化某些元函数或 typedef。但是,许多类型定义或元函数在 List<>
和 List<Ts...>
.
中具有相同的实现
示例:
template<typename...> struct List;
template<> struct List<>
{
using Type = List<>; // Redundant
using Tuple = std::tuple<>; // Redundant
// ...other redundant typedefs...
template<typename TList> using Append = TList; // Non-redundant
// ...other non-redundant typedefs...
};
template<typename... Ts> struct List
{
using Type = List<Ts...>; // Redundant
using Tuple = std::tuple<Ts...>; // Redundant
// ...other redundant typedefs...
template<typename TList>
using Append = AppendImpl<Type, TList>; // Non-redundant
// ...other non-redundant typedefs...
};
如您所见,List<>
和 List<Ts...>
之间的一些 typedef 是多余的。
我想做的是类似这样的:
template<typename...> struct List;
template<typename... Ts> struct ListBase
{
using Type = List<Ts...>;
using Tuple = std::tuple<Ts...>;
};
template<> struct List<> : public ListBase<>
{
template<typename TList> using Append = TList;
};
template<typename... Ts> struct List : public ListBase<Ts...>
{
template<typename TList>
using Append = AppendImpl<Type, TList>;
};
// The lines below should be valid code:
using X0 = List<>::Type;
using X1 = List<int, char, int>::Type;
using X2 = List<>::Tuple;
using X3 = List<char, char>::Tuple;
using X4 = List<>::Append<List<int, float>>;
using X5 = List<int>::Append<List<float>>;
不幸的是,typedefs do not propagate from the base class to the derived one。正如 sbabbi 在评论中所说,您必须求助于使用 完整限定名来引用基础 class 中的 typedef ,这对于我正在设计的 List<...>
class 是不可接受的。
有什么方法可以避免这种重复而不求助于宏吗?
反过来如何,将所有通用内容保留在 List
主模板中,然后使用一个单独的模板,对空参数包进行专门化处理,以处理不同的部分,例如作为 Append
?
template<typename... Ts> struct ListAppend
{
template<typename TList>
using Append = AppendImpl<Ts..., TList>;
};
template<> struct ListAppend<>
{
template<typename TList>
using Append = TList;
};
template<typename... Ts> struct List
{
using Type = List<Ts...>;
using Tuple = std::tuple<Ts...>;
template<typename TList>
using Append = typename ListAppend<Ts...>::Append<TList>;
};
现在只需要对不相同的部分使用特化,不要重复任何东西。
您可以通过在 List
class 模板中添加一个简单的 using
语句来避免大量冗余代码:using typename ListBase<Ts...>::Type;
您仍然必须为您在 ListBase
中声明的每种类型执行此操作,但是您可以在所有后续模板特化中自由使用这些类型名称。这是一个代码示例来阐明我的意思:
#include <tuple>
using namespace std;
template<typename... Ts> struct ListBase
{
using Type = ListBase<Ts...>;
using Tuple = tuple<Ts...> ;
};
template<typename... Ts> struct List : public ListBase<Ts...>
{
using typename ListBase<Ts...>::Type;
template<typename TList>
using Append = List<Type, TList>;
//more stuff using Type
};
template <> struct List<> : public ListBase<>
{
template<typename TList>
using Append = TList;
using something = Type;
};
int main() {
using X0 = List<>::Type;
using X1 = List<int, char, int>::Type;
using X2 = List<>::Tuple;
using X3 = List<char, char>::Tuple;
using X4 = List<>::Append<List<int, float>>;
using X5 = List<int>::Append<List<float>>;
return 0;
}
我希望这是解决您问题的可行方法。
此致,Marcel Meißner
我认为你做得太多(而且是错误的)。
您的代码
template<typename... Ts> struct List
{
using Type = List<Ts...>; // Redundant
using Tuple = std::tuple<Ts...>; // Redundant
};
适用于空参数包。但也有一些改进:
using Type=List
在模板中就足够了。您不需要重复所有参数
您可以在 class 之外实现功能:
template<typename List>
struct to_tuple_impl;
template<typename... Ts>
struct to_tuple_impl<List<Ts...>> {
using Type = std::tuple<Ts...>;
};
template<typename List>
using to_tuple = typename to_tuple_impl<List>::Type;
其他功能可以通过类似的方式实现:
- 模板元函数声明
- 使用可变参数和逻辑对您的序列进行部分专业化
- 方便使用的模板别名
可以找到一个 运行 示例 here。
我正在我的一个库中创建一个面向元编程的小型模块,它使用 List<Ts...>
class 进行编译类型列表操作。
我用空参数包专门化 List
以专门化某些元函数或 typedef。但是,许多类型定义或元函数在 List<>
和 List<Ts...>
.
示例:
template<typename...> struct List;
template<> struct List<>
{
using Type = List<>; // Redundant
using Tuple = std::tuple<>; // Redundant
// ...other redundant typedefs...
template<typename TList> using Append = TList; // Non-redundant
// ...other non-redundant typedefs...
};
template<typename... Ts> struct List
{
using Type = List<Ts...>; // Redundant
using Tuple = std::tuple<Ts...>; // Redundant
// ...other redundant typedefs...
template<typename TList>
using Append = AppendImpl<Type, TList>; // Non-redundant
// ...other non-redundant typedefs...
};
如您所见,List<>
和 List<Ts...>
之间的一些 typedef 是多余的。
我想做的是类似这样的:
template<typename...> struct List;
template<typename... Ts> struct ListBase
{
using Type = List<Ts...>;
using Tuple = std::tuple<Ts...>;
};
template<> struct List<> : public ListBase<>
{
template<typename TList> using Append = TList;
};
template<typename... Ts> struct List : public ListBase<Ts...>
{
template<typename TList>
using Append = AppendImpl<Type, TList>;
};
// The lines below should be valid code:
using X0 = List<>::Type;
using X1 = List<int, char, int>::Type;
using X2 = List<>::Tuple;
using X3 = List<char, char>::Tuple;
using X4 = List<>::Append<List<int, float>>;
using X5 = List<int>::Append<List<float>>;
不幸的是,typedefs do not propagate from the base class to the derived one。正如 sbabbi 在评论中所说,您必须求助于使用 完整限定名来引用基础 class 中的 typedef ,这对于我正在设计的 List<...>
class 是不可接受的。
有什么方法可以避免这种重复而不求助于宏吗?
反过来如何,将所有通用内容保留在 List
主模板中,然后使用一个单独的模板,对空参数包进行专门化处理,以处理不同的部分,例如作为 Append
?
template<typename... Ts> struct ListAppend
{
template<typename TList>
using Append = AppendImpl<Ts..., TList>;
};
template<> struct ListAppend<>
{
template<typename TList>
using Append = TList;
};
template<typename... Ts> struct List
{
using Type = List<Ts...>;
using Tuple = std::tuple<Ts...>;
template<typename TList>
using Append = typename ListAppend<Ts...>::Append<TList>;
};
现在只需要对不相同的部分使用特化,不要重复任何东西。
您可以通过在 List
class 模板中添加一个简单的 using
语句来避免大量冗余代码:using typename ListBase<Ts...>::Type;
您仍然必须为您在 ListBase
中声明的每种类型执行此操作,但是您可以在所有后续模板特化中自由使用这些类型名称。这是一个代码示例来阐明我的意思:
#include <tuple>
using namespace std;
template<typename... Ts> struct ListBase
{
using Type = ListBase<Ts...>;
using Tuple = tuple<Ts...> ;
};
template<typename... Ts> struct List : public ListBase<Ts...>
{
using typename ListBase<Ts...>::Type;
template<typename TList>
using Append = List<Type, TList>;
//more stuff using Type
};
template <> struct List<> : public ListBase<>
{
template<typename TList>
using Append = TList;
using something = Type;
};
int main() {
using X0 = List<>::Type;
using X1 = List<int, char, int>::Type;
using X2 = List<>::Tuple;
using X3 = List<char, char>::Tuple;
using X4 = List<>::Append<List<int, float>>;
using X5 = List<int>::Append<List<float>>;
return 0;
}
我希望这是解决您问题的可行方法。
此致,Marcel Meißner
我认为你做得太多(而且是错误的)。
您的代码
template<typename... Ts> struct List
{
using Type = List<Ts...>; // Redundant
using Tuple = std::tuple<Ts...>; // Redundant
};
适用于空参数包。但也有一些改进:
using Type=List
在模板中就足够了。您不需要重复所有参数您可以在 class 之外实现功能:
template<typename List> struct to_tuple_impl; template<typename... Ts> struct to_tuple_impl<List<Ts...>> { using Type = std::tuple<Ts...>; }; template<typename List> using to_tuple = typename to_tuple_impl<List>::Type;
其他功能可以通过类似的方式实现:
- 模板元函数声明
- 使用可变参数和逻辑对您的序列进行部分专业化
- 方便使用的模板别名
可以找到一个 运行 示例 here。