通过继承避免在 类 之间重复 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