【问题标题】:Generic lambda vs generic function give different behaviour泛型 lambda 与泛型函数给出不同的行为
【发布时间】:2019-08-17 10:24:40
【问题描述】:

以下代码为例

#include <algorithm>

namespace baz {
    template<class T>
    void sort(T&&){}
}

namespace boot {
    const auto sort = [](auto &&){};
}

void foo (){
    using namespace std;
    using namespace baz;
    sort(1);
}

void bar(){
    using namespace std;
    using namespace boot;
    sort(1);
}

我预计既然foo 已编译,那么bar 也应编译。令我惊讶的是,foo 编译正确,barsort 函数的模糊调用存在问题。我在这里做一些非法的事情还是编译器应该采取的正确方式?如果是这样,为什么会如此不同。我虽然可以将泛型 lambda 视为泛型函数的语法糖。

live example

【问题讨论】:

  • Lambda 不参与 ADL
  • 这不是 ADL。 int 参数不来自任何命名空间。
  • 这真的应该模棱两可吗? std::sort() 不接受 1 个参数作为输入,它至少需要 2 个,那么为什么编译器甚至将其视为仅传递 1 个参数值的调用的候选者?
  • 肯定有一些关于 lambda 引入的额外间接层。在第一个示例中,调用::baz::sort,但在第二个示例中,它必须找到::boot::mystery_lambda_type::operator()。这个额外的步骤可能是导致首先考虑std::sort 的原因。我面前没有标准,所以不能确定。

标签: c++ lambda c++14


【解决方案1】:

这里的问题不是对sort 的调用不明确,而是名称sort 不明确。名称查找发生在重载解析之前。

我相信相关部分是[basic.lookup]/1,具体

[…] 通过名称查找找到的声明要么都表示同一个实体,要么都表示函数或函数模板;在后一种情况下,声明被称为形成一组重载函数([over.load])。 […]

在您的情况下,名称sort 表示对象boot::sort 以及重载函数集std::sort。因此,名称查找失败。

例如,您的代码与您编写的代码确实没有什么不同

namespace baz {
    int a;
}

namespace boot {
    int a;
}

void foo() {
    using namespace baz;
    using namespace boot;
    a = 42;  // error: reference to 'a' is ambiguous
}

Try it out here;将此与a case that actually has an ambiguous function call 进行比较;请注意错误消息与您的情况相同,特别是指名称本身不明确,而不是函数调用。

【讨论】:

  • 我认为这实际上是正确的答案。我想补充一点,如果模板函数 sort 和 lambda sort 都在同一个命名空间中声明,那将是一个错误。在同一个命名空间中不能有同名的函数和非函数。所以永远不会有一个重载集同时具有真正的函数和类似函数的对象。
  • 对我来说似乎是一个正确的答案。如果有什么办法可以解决我的问题,我会感谢评论/回答编辑。
  • @Scheff 确实,我一定以某种方式混淆了 URL。现在应该修好了。感谢您指出这一点!
  • @bartop 你能不能只删除 using 指令和/或使用完全限定名称,例如 baz::sort!?
  • @MichaelKenzel 当然可以,我现在就可以。尽管我仍然想知道是否有不同的方法来避免这种歧义
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-21
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多