重载解析无法从不同的命名空间找到“operator+”

Luk*_*dič 3 c++

在下面的代码示例中,我们有两个类XY,两者都可以隐式转换为n1::BaseBase支持加法,所以我认为XY应该通过转换为Base. 相反,他们仅在其模板参数是时才支持它Base(即使该模板参数未在任何地方使用)。

谁能解释这是为什么吗?如果您能给我指出该标准的一部分或链接相关的 cppreference.com 文章,我会加分。

X如果和Y全部支持加法或不支持加法,这对我来说将是直观的。但我不明白为什么它们只使用适当的模板参数进行编译。如果您不确定为什么这让我感到困惑,我很乐意为您提供更多说明。我猜它与 ADL(参数相关查找)有关,但我不确定。

Godbolt 链接:https://godbolt.org/z/xe3enE9Tf

代码:

#include <iostream>

namespace n1 {
struct Base {};

int operator+(Base const&, int other) { return other; }
}

using n1::Base;

// Uncommenting this would fix the error below.
// using n1::operator+;

template <class = Base>
struct X {
    Base b;
    operator Base() { return b; }
};

template <class = void>
struct Y {
    Base b;
    operator Base() { return b; }
};

int main() {
    std::cout << Base{} + 3;
    std::cout << X{} + 3; // Compiles
    std::cout << Y<Base>{} + 3; // Also compiles
    std::cout << Y{} + 3; // Doesn't compile
    std::cout << X<void>{} + 3; // Also doesn't compile
}
Run Code Online (Sandbox Code Playgroud)

Luk*_*dič 5

立即回答我的问题感觉很愚蠢,但当我阅读更多有关 ADL 的内容后,我发现了这条线。来自 cppreference (强调我的):

\n
\n

...

\n

否则,对于函数调用表达式中的每个参数,都会检查其类型以确定它将添加到查找中的关联的命名空间和类集。

\n

...

\n

3) 对于类型为类模板特化的参数,除了类规则之外,还会检查以下类型,并将其关联的类和命名空间添加到集合中。

\n

\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0\xc2\xa0a)为类型模板参数提供的所有模板参数的类型(跳过非类型模板参数和跳过模板模板参数)。

\n
\n

简而言之,模板参数的命名空间XY添加到关联的命名空间集中。如果参数来自n1n1::operator+则变为可见。

\n

  • 有时就是这样。写下问题通常会泄露您需要的一些信息,但并非总是在您发布问题之前。 (5认同)
  • 这是正式规则:https://eel.is/c++draft/basic.lookup.argdep#3.2(cppreference 只是一个释义) (3认同)