【问题标题】:A function with a std::function parameter does not accept a lamba function带有 std::function 参数的函数不接受 lambda 函数
【发布时间】:2016-04-02 03:28:37
【问题描述】:

我正在尝试通过在我自己的双向链表集合上实现 std::iterator 并尝试创建自己的 sort 函数来对其进行排序,从而更加熟悉 C++11 标准。

我希望sort 函数通过使sort 接受std::function 来接受lamba 作为排序方式,但它无法编译(我不知道如何实现move_iterator,因此返回集合的副本而不是修改传递的集合)。

template <typename _Ty, typename _By>
LinkedList<_Ty> sort(const LinkedList<_Ty>& source, std::function<bool(_By, _By)> pred)
{
    LinkedList<_Ty> tmp;
    while (tmp.size() != source.size())
    {
        _Ty suitable;
        for (auto& i : source) {
            if (pred(suitable, i) == true) {
                suitable = i;
            }
        }
        tmp.push_back(suitable);
    }
    return tmp;
}

我对函数的定义有错吗?如果我尝试调用该函数,则会收到编译错误。

LinkedList<std::string> strings{
    "one",
    "two",
    "long string",
    "the longest of them all"
};

auto sortedByLength = sort(strings, [](const std::string& a, const std::string& b){
    return a.length() < b.length();
});

错误:没有函数模板“sort”的实例与参数匹配 列表参数类型为:(LinkedList, lambda []bool (const std::string &a, const std::string &)->bool)

补充资料,编译也报如下错误:

错误 1 错误 C2784: 'LinkedList<_ty> sort(const LinkedList<_ty> &,std::function)' : 不能 推导出 'std::function&lt;bool(_By,_By)&gt;' 的模板参数


更新:我知道排序算法不正确并且不会做想要的事情,我无意让它保持原样,并且一旦声明正确,修复它也没有问题.

【问题讨论】:

    标签: c++11 visual-studio-2013 lambda std-function


    【解决方案1】:

    问题是像这样在std::function 内部使用的_By 不能从lambda 闭包中推断出来。您需要传入一个实际的 std::function 对象,而不是 lambda。请记住,lambda 表达式的类型是未命名的类类型(称为闭包类型),不是std::function。

    你做的有点像这样:

    template <class T>
    void foo(std::unique_ptr<T> p);
    
    foo(nullptr);
    

    在这里,也无法从参数中推断出T。

    标准库通常如何解决这个问题:它不会以任何方式将自己限制为std::function,而只是将谓词的类型作为其模板参数:

    template <typename _Ty, typename _Pred>
    LinkedList<_Ty> sort(const LinkedList<_Ty>& source, _Pred pred)
    

    这样就可以推断出闭包类型,一切正常。

    请注意,您根本不需要 std::function — 只有当您需要存储一个仿函数或通过运行时接口传递它时才需要它(不是像模板那样的编译时)。


    旁注:您的代码使用的是为编译器和标准库保留的标识符(标识符以下划线开头,后跟大写字母)。这在 C++ 中是不合法的,您应该避免在代码中使用此类保留标识符。

    【讨论】:

    • 谢谢 Angew,这确实有效。在您引入模板之前,我对 C++ 非常满意,这基本上意味着我根本无法使用 C++ 编程。也感谢旁注,来自 PHP 世界,我们真的没有这样的东西。非常感谢。
    • 顺便说一句,只是命名约定有问题,对吗?不可能仅仅因为我按照我的方式命名模板参数,它们就会干扰标准库。或者模板是否有一些特殊的怪癖可能会破坏这一切?
    • @DavidPacker 这可能是一个真正的问题。这是因为标准库允许将此类名称用于任何目的,包括宏。想象一下您的代码将如何处理标准库标头中某处的 #define _By (void) 之类的内容...
    • @Angew 一个关于 lambda 和 std::function 的附带问题。使函数类型成为模板参数确实是标准库中的做法,但我认为 lambda 可以转换为具有匹配签名的 std:: 函数对象。我错了吗,还是 OP 的 lambda 的原始问题与带有 _By=string 的 std::function 参数的签名不匹配与带有 const string& 的 lambda 签名有关?
    • @DavidPacker 标准库不仅可以使用这样的名称,而且几乎必须这样做。否则,它可能会遇到相反的问题: 用户定义的宏搞乱了它自己的内部结构。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多