使用外部定义的模板类型作为模板参数的更通用模板的模板别名
Template alias of a more generic template using externally defined template type as a template parameter
我想采用一个定义良好的模板类,它依赖于 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_T
和Args_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()>;
- 部分定义/别名模板模板参数
- 告诉c++编译器该参数没有别名
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 模板模板参数和模板别名:编译器错误?
- 为模板参数包添加别名
- C++使用默认模板参数键入别名和转发声明
- 缺少别名模板C++参数列表
- 使用外部定义的模板类型作为模板参数的更通用模板的模板别名
- 必须非常量别名参数及其默认参数常量
- 作为模板参数 c++ 给出的类的别名模板
- 使用其他模板类型参数作为要在函数签名中使用的类型别名声明
- 参数化类的别名(或类型定义)内部类
- C++别名的模板参数包扩展
- 如何简化模板模板参数中的enable_if别名
- 包含可变参数包的第一个可转换类型的别名的结构
- C++ 11 个模板,参数包的别名
- 为什么模板引用类型不能用作模板类型别名参数?
- 具有模板类默认参数的 C++17 别名模板
- 如何用可变数量的参数别名一个函数