我正在尝试一些简单的基于模板的设计工作,并偶然发现了模板相互依赖性。现在我知道我可以使用虚拟函数和(在这种特定的人工情况下)通过将 EventHandler 方法转换为模板而不是整个类来解决此问题。但是,有没有办法拥有两个相互依赖的模板,前提是它们只使用指向彼此的指针?
这是简化的示例:
typename MySocket;
template<typename SocketClass> struct EventHandler {
void receiveCallback(SocketClass *s) {
}
};
template <typename HandlerType> class Socket {
HandlerType *handler;
};
typedef EventHandler<MySocket> MyHandler ;
typedef Socket<MyHandler> MySocket ;
MyHandler h;
MySocket socket;
int main() {
return 0;
}
对于此代码,编译器给出一个错误,指出套接字已重新定义。有什么想法吗?C++11/14对我来说很好。
鉴于您使用的语法,您要做的事情是不可能的。
也就是说,在将适当的参数传递给模板之前,MySocket
作为类型不存在。
由于MySocket
依赖于MyHandler
,而又取决于你有一个循环依赖MySocket
,所以这是行不通的。
我怀疑您随后试图通过将MySocket
作为类型名来向前声明来解决此问题,这C++无效。
不过,有一种方法可以解决此问题,那就是使用模板模板参数。
模板模板参数允许您将另一个模板作为参数传递给模板
template<template<typename> class SocketT>
struct EventHandlerT;
这里SocketT
是一个模板本身,采用 1 个模板参数(因此名称模板模板参数)
在EventHandlerT
中,您可以定义一个具体类型Socket
,它使用EventHandlerT
作为SocketT
所需的模板参数。
template<template<typename> class SocketT>
struct EventHandlerT;
{
using Socket = SocketT<EventHandlerT>; // Socket is now a concrete type
};
当您想要创建Socket
的实例时,您可以使用内部定义的实例EventHandlerT
using EventHandler = EventHandlerT<SocketT>;
using Socket = EventHandler::Socket;
下面是一个工作示例:
template<template<typename> class SocketT>
struct EventHandlerT
{
using Socket = SocketT<EventHandlerT>;
void receiveCallback(Socket* s)
{
}
};
template <typename HandlerT>
struct SocketT
{
HandlerT* handler;
};
int main()
{
using EventHandler = EventHandlerT<SocketT>;
using Socket = EventHandler::Socket;
EventHandler handler;
Socket socket;
socket.handler = &handler;
handler.receiveCallback(&socket);
return 0;
}