使用外部定义的模板类型作为模板参数的更通用模板的模板别名
Template alias of a more generic template using externally defined template type as a template parameter
我想采用一个定义良好的模板 class,它依赖于 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
的特定版本减去第一个模板参数加上使用现有模板作为更通用模板的特定模板参数。
我会问,"is this poor design?,"但我觉得这个概念足以解决我想解决的问题。我只是不明白到底该怎么做。谁能指出我正确的方向?再一次,我讨厌问。弄清楚这个很头疼。提前致谢!
我不会将模板参数列为 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
我们也可以传递具有更多参数的模板,只要它们具有默认值即可。
要在 ISignalEmitter
中获得 Return_T
和 Args_T...
,我们使用偏特化。
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()>;
我想采用一个定义良好的模板 class,它依赖于 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
的特定版本减去第一个模板参数加上使用现有模板作为更通用模板的特定模板参数。
我会问,"is this poor design?,"但我觉得这个概念足以解决我想解决的问题。我只是不明白到底该怎么做。谁能指出我正确的方向?再一次,我讨厌问。弄清楚这个很头疼。提前致谢!
我不会将模板参数列为 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
我们也可以传递具有更多参数的模板,只要它们具有默认值即可。
要在 ISignalEmitter
中获得 Return_T
和 Args_T...
,我们使用偏特化。
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()>;