使用std :: function时,编译器无法推断出类型

时间:2017-04-25 19:11:30

标签: c++ overloading type-deduction

所以,我有一个方法及其对类的重载,如下所示:

bool my_for_each(someIterator begin, someIterator end, bool (*_lambda)(someIterator));

void my_for_each(someIterator begin, someIterator end, void (*_lambda)(someIterator));

正如您所看到的,唯一的区别是传递函数的签名,即其返回类型。 虽然我称之为上面的代码完全正常:

my_for_each(iteratorBegin, iteratorEnd, [](someIterator) {; }); // calls void version

my_for_each(iteratorBegin, iteratorEnd, [](someIterator)->bool {return false; }); // calls bool version

...,如果我按如下方式编写my_for_each函数:

bool my_for_each(someIterator begin, someIterator end, std::function<bool(someIterator)> _lambda);

void my_for_each(someIterator begin, someIterator end, std::function<void(someIterator)> _lambda);

如果我以相同的方式调用函数(C2668模糊调用重载函数),则代码无法编译。虽然,如果我手动转换函数:

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<void(someIterator)>>([](someIterator) {; })); //calls void version

my_for_each(iteratorBegin, iteratorEnd, static_cast<std::function<bool(someIterator)>>([](someIterator) -> bool { return false; })); //calls bool version

代码完美无缺。所以我只是想知道:

  1. 为什么普通函数指针类型扣除比std模板“更强”?
  2. 是否还有一些解决方法仍然使用更通用的版本,而不是手动转换参数?
  3. 编译器是VS2015。

    谢谢,祝你有愉快的一天!

2 个答案:

答案 0 :(得分:3)

std::function和lambdas具有不同的类型,这意味着第二个示例需要从lambda的类型到std::function的隐式转换。

问题是返回bool的lambda可以隐式转换为std::function<bool(T)>std::function<void(T)>,因此两次重载都是调用同样有效的选择,导致歧义错误。当您手动将它们转换为正确的std::function时,明确解决了歧义。

修改:解决方法

您可以通过提供接受任何类型的可调用类型的附加模板化重载来解决此问题,推导出该可调用类型的返回类型并自动执行强制转换。我已将someIterator更改为模板参数以获得通用性。由于您尚未提供my_for_each函数的实现详细信息,因此我省略了这些实现。由于您似乎只想支持voidbool返回类型,因此我提供了static_assert来生成明确的编译器错误,以防提供不支持的返回类型。< / p>

#include <functional>
#include <type_traits>

// Implement for std::function<bool(iter)>
template<class I>
bool my_for_each(I begin, I end, std::function<bool(I)> lambda);

// Implement for std::function<void(iter)>
template<class I>
void my_for_each(I begin, I end, std::function<void(I)> lambda);

// Dispatch to the right overload
template<class T, class I>
auto my_for_each(I begin, I end, T&& lambda)
{
    using return_type = decltype(lambda(begin));    // Obtain the return type of lambda
    static_assert(std::is_same<return_type, bool>::value || std::is_same<return_type, void>::value,
        "my_for_each only accepts function objects that return void or bool");
    using function_type = std::function<return_type(I)>;    // The type to cast lambda to
    return my_for_each(begin, end, function_type(std::forward<T>(lambda))); // Preform the cast
}

答案 1 :(得分:2)

原因是非捕获lambda只能转换为函数指针,它接受使用类型的参数。

另一方面,std::function有一个模板化的构造函数,它接受所有东西。因此,std::function<bool...>std::function<void ...>都可以从lambda中创建,以便重载my_for_each。 (注意,虽然不可能创建这些对象。)