避免在具有继承的类之间重复typedef

时间:2015-02-27 14:49:19

标签: c++ templates inheritance typedef c++14

我在我的一个库中创建一个面向元编程的小模块,它使用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>是不可接受的。我是设计课程。

有没有办法可以避免这种重复而不诉诸宏?

3 个答案:

答案 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