在我们的 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 专家,所以我的一些假设可能是错误的。
有没有一个好的(更好?)的方法来指示扩展应该在哪种模式下使用并添加/删除所需的功能?
您可以将
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=;
};