我在我的一个库中创建一个面向元编程的小模块,它使用List<Ts...>
类进行编译类型列表操作。
我使用空参数包专门化List
以专门化某些元函数或typedef。但是,很多typedef或metafunctions在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...
};
如您所见,某些typedef在List<>
和List<Ts...>
之间是多余的。
我想做的是这样的:
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 在评论中所说的那样,您必须使用完整限定名称来引用基类中的typedef,这对于{{1>是不可接受的。我是设计课程。
有没有办法可以避免这种重复而不诉诸宏?
答案 0 :(得分:2)
如何以相反的方式执行此操作,将所有常见内容保留在List
主模板中,然后使用单独的模板(对于空参数包具有专门化),用于不同的部分,例如{ {1}}?
Append
现在你只需要对不相同的部分使用专业化,而不是重复任何事情。
答案 1 :(得分:2)
您可以通过向using
课程模板添加简单的List
语句来避免大量冗余代码: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;
}
我希望这是解决问题的可行方案 此致,MarcelMeißner
答案 2 :(得分:1)
我认为你做的很多(而且是错误的)。
您的代码
template<typename... Ts> struct List
{
using Type = List<Ts...>; // Redundant
using Tuple = std::tuple<Ts...>; // Redundant
};
适用于空参数包。但是有一些改进:
using Type=List
就足够了。您不需要重复所有参数您可以在班级之外实现功能:
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。