【发布时间】:2023-01-15 14:36:26
【问题描述】:
我在一个类中声明了一个模板成员函数,它根据类型调用正确的成员函数,并希望通过添加一个成员函数在子类中为其添加一些功能,如下面的 main.cpp 示例所示:
#include <iostream>
class A
{
public:
template <typename T>
void handleSocketData(const T& t)
{
handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
};
class B: public A
{
public :
void handleData(std::string data) const
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData<int>(30);
b.handleSocketData<std::string>("Hi");
return 0;
}
我的问题是 b.handleSocketData<QString>("Hi"); 实际上确实在 A 类中生成了一个新的模板实例,如命令 /usr/bin/clang++ -DQT_CORE_LIB -isystem /usr/include/qt6/QtCore -isystem /usr/include/qt6 -isystem /usr/lib64/qt6/mkspecs/linux-g++ -g -std=gnu++17 -Xclang -ast-print -fsyntax-only main.cpp 的输出所示:
class A {
public:
template <typename T> void handleSocketData(const T &t) {
this->handleData(t);
}
template<> void handleSocketData<int>(const int &t) {
this->handleData(t);
}
template<> void handleSocketData<std::basic_string<char>>(const std::basic_string<char> &t) {
<recovery-expr>(this->handleData, t);
}
void handleData(int data) {
std::cout << data << std::endl;
}
};
class B : public A {
public:
void handleData(std::string data) const {
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[]) {
A a;
B b;
a.handleSocketData<int>(30);
b.handleSocketData<std::string>("Hi");
return 0;
}
所以现在我有一个编译错误,说没有找到函数 handleData(const std::string& data),这是正常的。
我们发现的解决方法是定义一个双参数模板,将子类作为参数(一种访问者模式):
#include <iostream>
class A
{
public:
template <typename T, typename U>
void handleSocketData(U& u, const T& t)
{
u.handleData(t);
}
void handleData(int data)
{
std::cout << data << std::endl;
}
};
class B: public A
{
public :
void handleData(std::string data)
{
std::cout << data << std::endl;
}
};
int main(int argc, char *argv[])
{
A a;
B b;
a.handleSocketData<int>(a, 30);
b.handleSocketData<std::string>(b, "Hi");
return 0;
}
你怎么认为 ?有更清洁的方法吗?
【问题讨论】:
-
从来不知道班级有性别。如果将其更改为子类怎么办?
-
您的解决方案看起来像 deducing this (C++23)。
-
我的假设是否正确,模板化的
handleSocketData出于某种原因需要存在(满足外部 API 或其他)?因为对于您提供的简单示例,由于重载解析不需要它:godbolt.org/z/x64osr3M4