向可变参数类模板添加可选参数 (C++14)

问题描述 投票:0回答:1

在我们的 C++14 代码库中,我们的模块有两种类型的扩展。将 A 组想象为启动时运行类型,将 B 组想象为关闭时运行类型。该模块只需提供所有扩展的列表,并根据它们的组执行它们。模块自动区分它们属于哪一组:A 组具有

runAtStartUp
功能,B 组具有
runAtShutDown
功能。此检查是通过编译时的模板检查完成的。 (如果扩展程序具有这两种功能,则它将在启动和关闭时运行,但目前不存在这样的扩展程序)。

我们的一个扩展目前总是在关闭时运行。这是一个可变参数类模板,如下所示:

template <typename... Ts>
class myExtension{
...
void runAtShutDown();
}

我们收到请求,希望能够在启动时运行它,而不更改默认行为。

为了能够在启动时运行它,我们需要删除

runAtStartUp
函数并添加
runAtShutDown
函数。我知道如何通过
std::enable_if
检查编译时是否有条件来做到这一点。我可以在模板参数列表中添加一个 bool 标志来指示我要使用哪种模式:

template <bool mode, typename... Ts>
class myExtension{

  template <bool enabled=mode>
  std::enable_if<enabled, void>
  runAtStartUp();

  template <bool enabled=mode>
  std::enable_if<!enabled, void>
  runAtShutDown();

}

但是,我必须将此标志添加到使用此类的所有实例中。这将需要对想要继续使用旧的默认行为的模块进行大量更改。我正在寻找一种仅在使用新的非默认行为时才需要更改的方法。

从现有类继承似乎不是解决方案,因为我还需要删除现有的

runAtShutDown
函数,而不仅仅是添加
runAtStartUp
。如果可以的话,我现在知道怎么做了。

到目前为止,我想到的最好的解决方案是创建一个既没有

runAt...
函数的基类,以及两个仅添加所需的
runAt...
函数的继承类。我还没有尝试过,所以我不是 100% 这确实有效。

我不是 TMP 专家,所以我的一些假设可能是错误的。

有没有一个好的(更好?)的方法来指示扩展应该在哪种模式下使用并添加/删除所需的功能?

c++ c++14 enable-if tmp
1个回答
1
投票

您可以将

myExtension
的实现重命名为新名称,例如
myExtensionEx
,它采用一个新的模板参数,用于决定何时运行不同的函数:

enum class when : int { NEVER, STARTUP, SHUTDOWN };

constexpr when operator|(when lhs, when rhs) {
    return static_cast<when>(static_cast<int>(lhs) | static_cast<int>(rhs));
}

template <when mode, when mask>
static constexpr bool is_on_v = static_cast<int>(mode) & static_cast<int>(mask);

template <when mode, class... Ts>
class myExtensionEx {
   public:
    template <bool enabled = is_on_v<mode, when::STARTUP>>
    std::enable_if_t<enabled, void> runAtStartUp() {
        std::cout << "StartUp\n";
    }

    template <bool enabled = is_on_v<mode, when::SHUTDOWN>>
    std::enable_if_t<enabled, void> runAtShutDown() {
        std::cout << "ShutDown\n";
    }
};

重命名完成后,您需要为

myExtension
的老用户提供一个像以前一样只调用
runAtShutDown()
的类。然后它可以从新类继承以获得所需的行为,因此您无需重复代码:

template <class... Ts>
class myExtension : public myExtensionEx<when::SHUTDOWN, Ts...> {
public:
    using myExtensionEx<when::SHUTDOWN, Ts...>::myExtensionEx;
    using myExtensionEx<when::SHUTDOWN, Ts...>::operator=;
};

演示

© www.soinside.com 2019 - 2024. All rights reserved.