假设int
和double
有函数ovelaods。
void Print(int v)
{
cout << v << endl;
}
void Print(double v)
{
cout << v << endl;
}
有一个函数可以作为上述函数中的一个可调用函数传入。
template<typename FnT>
void Function(int v, FnT&& fn)
{
fn(v);
}
但是下面的代码含糊不清:
Function(1, Print);
Compiller无法推断第二个参数的类型。这很容易解决:
Function(1, static_cast<void(*)(int)>(Print));
我相信存在更通用和优雅的方式来解决问题。当添加函数重载时,可以在STL算法中提出这个问题。
vector<int> v = { 1,2,3 };
for_each(v.begin(), v.end(), Print); // ambigous code
如何以漂亮的方式解决这个问题?
答案 0 :(得分:3)
将其包裹在函数对象中:
#include <iostream>
#include <utility>
void Print(int v)
{
std::cout << v << std::endl;
}
void Print(double v)
{
std::cout << v << std::endl;
}
template<typename FnT>
void Function(int v, FnT&& fn)
{
fn(v);
}
auto print_wrapper() {
return [](auto&&...args) -> decltype(auto)
{
return Print(std::forward<decltype(args)>(args)...);
};
}
int main()
{
Function(1, print_wrapper());
}
从理论上讲,我们在这里做的是使用绷带修复破损的设计。
更好的设计是将Print
的概念定义为模板函数对象。然后,我们可以专注于它,并根据我们内心的内容进行定制。
一个(非常完整的)模型是boost::hash<>
,这是任何人花费半天时间作为学习练习。
一个简单的例子:
#include <iostream>
#include <utility>
#include <string>
struct Printer
{
void operator()(const int& i) const {
std::cout << i << std::endl;
}
void operator()(const double& i) const {
std::cout << i << std::endl;
}
template<class Anything>
void operator()(const Anything& i) const {
custom_print(i);
}
};
struct Foo
{
};
void custom_print(Foo const& f)
{
std::cout << "a Foo" << std::endl;
}
template<typename X, typename FnT>
void Function(X const& x, FnT&& fn)
{
fn(x);
}
int main()
{
Function(1, Printer());
Function(1.0, Printer());
Function(Foo(), Printer());
}
答案 1 :(得分:2)
或者,您可以使用lambda:
Function(42, [](int i) {Print(i);});.