使用参数包专门化模板 类

Specializing Template Classes with Parameter Packs

我正在使用一组 classes 的继承。其中一个子 classes 接受 std::function(ReturnTy<ParamTypes...>) 以及 ParamTypes 参数。 class 签名和构造函数如下所示:

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,但它并不完全涵盖我正在尝试做的事情,因为该问题使用编译时整数作为模板参数,我在这里使用类型。它还涉及函数而不是 classes。我觉得我很接近,但我只需要一些帮助来使我的代码正常工作。

作为参考,这是我对其他专业的了解(缩写):

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);

问题是你们的专业水平相同(没有一个比另一个更专业)并且 Child<void> 两者都匹配。

如果您希望 Child<void> 匹配 Child<ReturnTy> 情况(否则解决方案简单而优雅:在第二个专业化中,将 ParamTypes... 列表拆分为 Par0 强制类型和其余 ParamTypes...) 我没有看到一个简单而优雅的解决方案。

目前,我能想到的最好的办法是添加一个间接级别(添加一个 Child_base class),同时添加一个模板参数来明确所需的解决方案。

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

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 派生的 class,不如将其定义为 using 的别名 Child_base

template <typename RT, typename ... PTs>
using Child = Child_base<RT, std::is_same_v<void, RT>, PTs...>;

也许用更合适的名称重命名 Child_base

问题是 Child<void> 匹配 2 个(部分)专业(其中 none 比另一个更专业):

  • template<class ReturnTy> class Child<ReturnTy>[ReturnTy = void]
  • template<class... ParamTypes> class Child<void, ParamTypes...> 空包。

你需要额外的专业化:

template<>
class Child<void> : public Interface
{
public:
    Child() = default;

// ....
private:
    std::function<void()> m_Function;
};

Demo