如何解决以下代码中的函数重载歧义问题

时间:2017-07-30 10:29:36

标签: c++ templates stl overloading

假设intdouble有函数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);

Live example

Compiller无法推断第二个参数的类型。这很容易解决:

Function(1, static_cast<void(*)(int)>(Print));

我相信存在更通用和优雅的方式来解决问题。当添加函数重载时,可以在STL算法中提出这个问题。

vector<int> v = { 1,2,3 };
for_each(v.begin(), v.end(), Print); // ambigous code

如何以漂亮的方式解决这个问题?

2 个答案:

答案 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);});.