使用外部定义的模板类型作为模板参数的更通用模板的模板别名

Template alias of a more generic template using externally defined template type as a template parameter

本文关键字:参数 别名 类型 定义 外部      更新时间:2023-10-16

我想采用一个定义良好的模板类,它依赖于 boost::signals2,并将其抽象为更深的通用层,这可以消除依赖性,允许使用不同的实现,但仍允许通过依赖更通用的接口而不是更具体的接口来使用更高级的函数。在我的重构中,我完全卡住了。而且,我已经知道我在这里有点不合时宜了。在这一年里,我才开始真正学习C++。但是,这有点有趣。但是我对模板的理解中缺少一些东西。首先,我正在处理的库将使用 C++17,我使用的是 clang++ (Mac(,并且取决于 Boost ~1.7.2 Signals2。

请考虑以下摘录:

#include <boost/signals2.hpp>
template<typename Functional_T, typename Return_T, typename ...Args_T>
using SignalHandler = typename Functional_T::template Functional_T<Return_T(Args_T...)>;
template<typename Connection_T>
struct SignalConnection; //no issues here, just wraps a private Connection_T with a getter/setter
template<typename Connection_T, typename Functional_T, typename Return_T, typename ...Args_T>
struct ISignalEmitter
{
protected:
virtual Return_T trigger(Args_T ...args) = 0;
public:
virtual void disconnectAll() = 0;
virtual SignalConnection<Connection_T> onSignal(SignalHandler<Functional_T, Return_T, Args_T...> &signalHandler) = 0;
virtual void cancelOnSignal(const SignalConnection<Connection_T> &connection) = 0;
};

但这就是我完全陷入困境的地方。我想定义的东西,在我的脑海中是这样的:

template<typename Return_T, typename ...Args_T>
using BoostSignals2SignalHandler = SignalHandler<boost::signals2::slot, Return_T, Args_T...>;

我想我们都知道会发生什么。slot需要模板参数。那么我该如何构建它才能让它工作呢?我尝试了各种各样的东西,但我被卡住了。我的下一个猜测是:

template<typename Return_T, typename ...Args_T>
using BoostSignals2SignalHandler = SignalHandler<template boost::signals2::slot::template, Return_T, Args_T...>;

我不想问,但我知道我不能成为第一个试图解决这个谜语的人。并且必须有一种方法以易于理解的方式思考这些模板,而不仅仅是猜测和测试。我有一个模板别名BoostSignals2SignalHandler它是SignalHandler减去第一个模板参数的特定版本,加上使用现有模板作为更通用模板的特定模板参数。

我会问,"这是糟糕的设计吗?"但我觉得这个概念足以解决我想解决的问题。我只是不明白到底该怎么做。谁能指出我正确的方向?再一次,我不想问。这个一直很头疼。提前感谢!

与其将您的模板参数列为Return_T, Args_T...,不如按照 Signals2 示例并使用函数类型的单个参数,例如SignalHandler中的Return_T(Args_T...).

然后,我们只需将Functional_T更改为模板模板参数即可。

template<template <typename> typename Functional_T, typename Signature_T>
using SignalHandler = Functional_T<Signature_T>;

现在传递给SignalHandler的第一个参数必须是可以使用 1 个模板参数进行配置的模板。由于您使用的是c++17因此我们也可以传递具有更多参数的模板,只要它们具有默认值。

为了获得Return_TArgs_T...ISignalEmitter我们使用部分专业化。

template<typename Connection_T, template <typename> typename Functional_T, typename Signature_T>
struct ISignalEmitter; // Base declaration to match the specialization against
template<typename Connection_T, template <typename> typename Functional_T, typename Return_T, typename ...Args_T>
struct ISignalEmitter<Connection_T, Functional_T, Return_T(Args_T...)> // Matching Return_T and Args_T against Signature_T
{
protected:
virtual Return_T trigger(Args_T ...args) = 0;
public:
virtual void disconnectAll() = 0;
virtual SignalConnection<Connection_T> onSignal(SignalHandler<Functional_T, Return_T(Args_T...)> &signalHandler) = 0;
virtual void cancelOnSignal(const SignalConnection<Connection_T> &connection) = 0;
};

此时,您可以像这样定义BoostSignals2SignalHandler

template<typename Signature_T>
using BoostSignals2SignalHandler = SignalHandler<boost::signals2::slot, Signature_T>;
using MySignalHandler = BoostSignals2SignalHandler<void()>;