MinGW64 和 MSVC 上函数解析的不同结果

Different result for function resolution on MinGW64 and MSVC

template <typename T>
int get_num(const T&)
{
    return 42;
}

struct Foo
{
    int i = get_num(*this);
};

int get_num(const Foo&)
{
    return 23;
}

int main()
{
    std::cout << Foo().i << std::endl; // MinGW64 - 42, MSVC - 23
    return 0;
}

MSVC 选择非模板get_num“重载”。它会成功 link 即使模板只是前向声明。 MinGW64 会选择默认模板实现。如果模板没有定义,将无法 link。

谁对谁错?标准是怎么说的?


但是这个版本对两个编译器产生相同的结果...为什么它不进入无限递归?

template <typename T>
int get_num(const T& t)
{
    std::cout << "Template version called" << std::endl;
    return get_num(t);
}

struct Foo
{
    int i = get_num(*this);
};

int get_num(const Foo&)
{
    std::cout << "Non-Template version called" << std::endl;
    return 23;
}

MSVC 输出:

Non-Template version called
23

MinGW64 输出:

Template version called
Non-Template version called
23

我认为使用 MSVC 时涉及到 ADL。

第一个例子,MinGW是正确的,MSVC是错误的:get_num调用只能考虑函数模板。

这是重载决议的问题,所以我将从子句[over]开始。 get_num(*this) 是一个普通的函数调用表达式,所以 [over.call.func] 适用:

In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls. The function declarations found by that lookup constitute the set of candidate functions.

“名称查找”在 [basic.lookup] 节中讨论。第 2 段:

A name "looked up in the context of an expression" is looked up as an unqualified name in the scope where the expression is found.

这里的一个复杂问题是 get_num(*this) 默认成员初始化表达式不会被任何东西使用,直到 Foo 的默认构造函数由其在 [=16= 中的 odr-use 隐式定义].但是查找是由表达式本身的代码位置确定的,无论它是否用于该隐式定义的过程中。

对于第二个代码示例,MinGW 再次正确:模板定义中看似递归的调用实际上调用了非模板函数。

这是 [temp.dep.res] 节中描述的依赖函数调用的“两阶段查找”的结果。简而言之,由于 t 的类型取决于模板参数,因此表达式 get_num(t) 中的名称 get_num 被视为从属名称。因此,对于函数模板的每个实例化,它有两种方法来寻找重载决议的候选者:找到 get_num 函数模板的普通直接方法,以及从实例化点开始的另一种查找。特化 get_num<Foo>main() 定义之后有实例化点,因此重载决议能够从实例化上下文中找到非模板,并且非模板赢得重载决议。

(依赖于参数的查找是与第二点相关的切线问题。ADL 适用于实例化上下文中的声明,但不适用于定义上下文中的声明。但这不是两个示例程序中行为的直接原因。 )

据我所知,

None 在 C++14 和最新草案之间发生了显着变化。