C/C++中重载函数取地址的方法
目录
1.现象
2.指定参数取函数地址
3.利用Qt的类QOverload
1.现象
函数重载在C/C++编码中是非常常见的,但是我们在std::bind或std::function绑定函数地址的时候,直接取地址,程序编译就会报错,示例如下:
class CFunc12345
{
public:
void func12345(int x) {
std::cout decltype(ptr)
{ return ptr; }
};
template
struct QOverload : QConstOverload, QNonConstOverload
{
using QConstOverload::of;
using QConstOverload::operator();
using QNonConstOverload::of;
using QNonConstOverload::operator();
template
Q_DECL_CONSTEXPR auto operator()(R (*ptr)(Args...)) const Q_DECL_NOTHROW -> decltype(ptr)
{ return ptr; }
template
static Q_DECL_CONSTEXPR auto of(R (*ptr)(Args...)) Q_DECL_NOTHROW -> decltype(ptr)
{ return ptr; }
};
顾名思义,模版类QNonConstOverload是取不带const的类成员函数的地址的,模版类QConstOverload是取带const的类成员函数的地址的,QOverload是取普通函数地址的,它们之间的关系如下图所示:
于是上面编译错误的代码可以修改为:
int main()
{
//方法2
CFunc12345 x1;
auto p = std::bind(QOverload::of(&CFunc12345::func12345), x1, std::placeholders::_1);
p(14124);
auto p1 = std::bind(QOverload::of(&func67890), std::placeholders::_1);
p1(33333333);
std::function p2(QOverload::of(&func67890));
p2(33333333);
return 0;
}
QOverload看似只有装有Qt环境才能用,其实把源码稍加修改就可以作为标准的C++类来用,修改后的COverload源码如下所示:
template
struct CNonConstOverload
{
template
auto operator()(R(T::* ptr)(Args...)) const -> decltype(ptr)
{
return ptr;
}
template
static auto of(R(T::* ptr)(Args...)) -> decltype(ptr)
{
return ptr;
}
};
template
struct CConstOverload
{
template
auto operator()(R(T::* ptr)(Args...) const) const -> decltype(ptr)
{
return ptr;
}
template
static auto of(R(T::* ptr)(Args...) const) -> decltype(ptr)
{
return ptr;
}
};
template
struct COverload : CConstOverload, CNonConstOverload
{
using CConstOverload::of;
using CConstOverload::operator();
using CNonConstOverload::of;
using CNonConstOverload::operator();
template
auto operator()(R(*ptr)(Args...)) const -> decltype(ptr)
{
return ptr;
}
template
static auto of(R(*ptr)(Args...)) -> decltype(ptr)
{
return ptr;
}
};
QOverload在Qt的信号槽中也用的比较多。信号槽连接时,使用基于字符串的语法,可以显式指定参数类型。因此,使用重载信号或槽的哪一个实例是明确的。相反,使用基于模版函数的语法,必须强制转换重载信号或槽,以告诉编译器要使用哪个实例。
例如,QLCDNumber有三个版本的display() 槽函数:
1.QLCDNumber::display(int)
2.QLCDNumber::display(double)
3.QLCDNumber::display(QString)
使用信号QSlider::valueChanged()和QLCDNumber::display(int)连接,可以有如下系列方法:
auto slider = new QSlider(this);
auto lcd = new QLCDNumber(this);
// String-based syntax
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
// Functor-based syntax, first alternative
connect(slider, &QSlider::valueChanged,
lcd, static_cast(&QLCDNumber::display));
// Functor-based syntax, second alternative
void (QLCDNumber::*mySlot)(int) = &QLCDNumber::display;
connect(slider, &QSlider::valueChanged,
lcd, mySlot);
// Functor-based syntax, third alternative
connect(slider, &QSlider::valueChanged,
lcd, QOverload::of(&QLCDNumber::display));
// Functor-based syntax, fourth alternative (requires C++14)
connect(slider, &QSlider::valueChanged,
lcd, qOverload(&QLCDNumber::display));
总的来说,QOverload是一个强大的工具,它使得在Qt中使用信号和槽机制时,处理函数重载的情况变得更加简单和直观。

