使用参数包来专门化模板类

时间:2020-02-06 22:01:36

标签: c++ class templates variadic-templates template-specialization

我正在使用带有一组类的继承。其中一个子类与std::function(ReturnTy<ParamTypes...>)参数一起使用ParamTypes。类签名和构造函数如下:

template<class ReturnTy, class... ParamTypes>
class Child : public Interface
{
public:
    Child(ReturnTy default_value, ParamTypes... args)
        : func_set_(false)
        , m_Args(std::make_tuple(std::forward<ParamTypes>(args)...))
        , m_ReturnValue(default_value)
    {}

private:
    bool func_set_;
    std::function<ReturnTy(ParamTypes...)> m_Funciton;
    std::tuple<ParamTypes...> m_Args;
    ReturnTy m_ReturnValue;
};

我的问题是我想专门研究没有参数的情况。此外,我还想专门研究ReturnTy=void并且有参数的情况。我找到了一个与我正在寻找的here接近的答案,但是它并不能完全涵盖我要执行的操作,因为该问题使用编译时整数作为模板参数,而我在使用类型。它还涉及函数而不是类。我感觉自己已经接近了,但是我需要一些帮助才能使我的代码正常工作。

作为参考,这是我对其他专业(简称)的看法:

template<class ReturnTy>
class Child<ReturnTy> : public Interface
{
public:
    Child(ReturnTy default_value)
        : // The same as first class without m_Args
    {}

private:
    // Same as first class without m_Args
};

template<class... ParamTypes>
class Child<void, ParamTypes...> : public Interface
{
public:
    Child(ParamTypes... args)
        : // Same as first class without m_ReturnValue

private:
    // Same as first class without m_ReturnValue
};



编辑
具体来说,该问题来自以下代码行:

Child<void> obj1(5);

2 个答案:

答案 0 :(得分:1)

问题是您的专长处于同一级别(没有人比另一个专长),并且Child<void>两者都匹配。

如果您希望Child<void>Child<ReturnTy>大小写匹配(否则解决方案简单而优雅:在第二种专业化方法中,将ParamTypes...列表拆分为Par0强制性类型和其他ParamTypes...)类型,我看不到简单而优雅的解决方案。

目前,我能想到的最好的办法就是添加一个间接级别(添加一个Child_base类),同时还添加一个模板参数以显式显示所需的解决方案。

也许可以用一种更简单的方式制作(抱歉,但是在这一刻,我可以尝试使用编译器),但是我可以想象如下

template <typename RT, bool, typename ... PTs>
class Child_base : public Interface
{
   // general case (no empy PTs... list and no void return type)
};

template <typename ... PTs>
class Child_base<void, true, PTs...> : public Interface
{
   // case return type is void (also empy PTs... list)
};

template <typename RT>
class Child_base<RT, false> : public Interface
{
   // case return type only, but not void, and empy PTs
};

template <typename RT, typename ... PTs>
class Child 
   : public Child_base<RT, std::is_same_v<void, RT>, PTs...> 
 {
 };

通过这种方式,Child<void>继承自Child_base<void, true>的第一个专业化的Child_base,但不匹配第二个专业化的专业。

我提出了另一种关于Child的方法:与其将其定义为派生自Child_base的类,不如尝试将其定义为using的{​​{1}}别名

Child_base

也许用更合适的名称重命名template <typename RT, typename ... PTs> using Child = Child_base<RT, std::is_same_v<void, RT>, PTs...>;

答案 1 :(得分:0)

问题是config/horizon.php匹配2个(部分)专业(其中没有一个比另一个更专业):

  • Child<void>template<class ReturnTy> class Child<ReturnTy>
  • [ReturnTy = void],带有空包装。

您因此需要额外的专业化:

template<class... ParamTypes> class Child<void, ParamTypes...>

Demo

相关问题