在c++模板中获取指针的目标类型



我编写了一个模板函数,该函数可以传递给QTcpServer或QBluetoothServer。它获取下一个挂起的连接,并绑定它的几个事件处理程序。(真正的函数也包含一些错误处理和其他内容,但它们与问题无关,所以我省略了它们(。

template <typename T> static void clientConnected(T * server) {
auto clientsocket = server->nextPendingConnection();

clientsocket将是QTcpSocket或QBluetoothSocket,具体取决于服务器的类型。

我可以使用公共基类QIODevicece绑定readyRead信号。

QObject::connect(clientsocket,&QIODevice::readyRead, [=](){readyRead(clientsocket);});

然而,对于断开的信号不存在这样的公共基类。因此,我需要知道clientsocket是指向什么类型的指针,以便选择要绑定的正确信号。我想出了。

QObject::connect(clientsocket,&std::remove_reference<decltype(*clientsocket)>::type::disconnected, [=](){readyRead(clientsocket);});

哪种方法有效,但似乎并不令人惊讶,有没有更简洁的方法来获取指针的目标类型?


根据要求,下面有一个最小的可编译示例,其中可以测试任何替代溶液。

#include <QTcpServer>
#include <QBluetoothServer>
#include <QTcpSocket>
#include <QBluetoothSocket>
template <typename T> static void clientConnected(T * server) {
auto clientsocket = server->nextPendingConnection();
QObject::connect(clientsocket,&std::remove_reference<decltype(*clientsocket)
}
void baz() {
QTcpServer * foo = new QTcpServer();
clientConnected(foo);
QBluetoothServer * bar = new QBluetoothServer(QBluetoothServiceInfo::RfcommP
clientConnected(bar);
}

使用编译

gcc -fPIC `pkg-config --cflags Qt5Bluetooth` `pkg-config --cflags Qt5Network` -c targettype.cpp

将左值(例如延迟clientsocket变量(传递给decltype()会返回一个引用类型,因此如果要使用decltype,则需要使用std::remove_referencestd::remove_pointer来访问被引用的类型,这是无法绕过的。

在C++14及更高版本中,您可以使用std::remove_reference_t<T>而不是std::remove_reference<T>::type(或使用std::remove_pointer_t<T>而不是std::remove_pointer<T>::type(,这将保存几个字符:

QObject::connect(
clientsocket,
&std::remove_reference_t<decltype(*clientsocket)>::disconnected,
[=](){ disconnected(clientsocket); }
);
QObject::connect(
clientsocket,
&std::remove_pointer_t<decltype(clientsocket)>::disconnected,
[=](){ disconnected(clientsocket); }
);

如果你真的想要更短的,你可以使用using别名:

template<typename T>
using no_ref = typename std::remove_reference<T>::type;
// = std::remove_reference_t<T>;
QObject::connect(
clientsocket,
&no_ref<decltype(*clientsocket)>::disconnected,
[=](){ disconnected(clientsocket); }
);
template<typename T>
using no_ptr = typename std::remove_pointer<T>::type;
// = std::remove_pointer_t<T>;
QObject::connect(
clientsocket,
&no_ptr<decltype(clientsocket)>::disconnected,
[=](){ disconnected(clientsocket); }
);

在C++17及更高版本中,可以使用if constexpr来区分这两种类型,例如:

auto handler = [=](){ disconnected(clientsocket); };
if constexpr (std::is_same_v<decltype(*clientsocket), QBluetoothSocket&>)
QObject::connect(clientsocket, &QBluetoothSocket::disconnected, handler);
else
QObject::connect(clientsocket, &QTcpSocket::disconnected, handler);

然而,有一个更简单的解决方案根本不需要使用decltype

template<typename T>
using signalType = void(T::*)();
template<typename T>
signalType<T> getDisconnectedSignal(T*)
{
return &T::disconnected;
}
QObject::connect(
clientsocket, 
getDisconnectedSignal(clientsocket),
[=](){ disconnected(clientsocket); }
);

只需使用std::remove_pointer(或C++14中的std::remove_pointer_t(。

using t = typename std::remove_pointer<int*>::type; // t = int.

最新更新