在解析分配给默认参数值的重载函数时,会考虑哪些函数集?

Jar*_*ock 13 c++ overloading

考虑下面的函数bar,其参数具有从重载调用初始化的默认值foo:

#include <iostream>

int foo(int x)
{
  std::cout << "foo(int)" << std::endl;
  return 0;
}

template<typename T>
void bar(T a, int x = foo(T(0))) {}

double foo(double x)
{
  std::cout << "foo(double)" << std::endl;
  return 0;
}

int main()
{
  bar<int>(1);
  bar<double>(1);
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

我希望这个程序输出

foo(int)
foo(double)
Run Code Online (Sandbox Code Playgroud)

对应于foobar实例化时可见的两个重载.

相反,当编译时g++-4.6,输出是

$ g++-4.6 -std=c++0x test.cpp; ./a.out 
foo(int)
foo(int)
Run Code Online (Sandbox Code Playgroud)

在实现与正常重载分辨率不同的默认参数值时是否考虑了过载集?这种情况是在ISO C++标准中描述的吗?

Jar*_*ock 6

该程序表明所考虑的函数集遵循正常的重载决策规则:

#include <iostream>

struct type1 {};
struct type2 {};

int foo(type1 x)
{
  std::cout << "foo(type1)" << std::endl;
  return 0;
}

template<typename T>
void bar(int x = foo(T())) {}

int foo(type2 x)
{
  std::cout << "foo(type2)" << std::endl;
  return 0;
}

int main()
{
  bar<type1>();
  bar<type2>();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译时g++-4.6,该程序输出:

$ g++ test_2.cpp ; ./a.out 
foo(type1)
foo(type2)
Run Code Online (Sandbox Code Playgroud)

换句话说,foobar实例化时通过ADL解析.

来自OP的代码的行为似乎是ADL不适用于诸如int和的原语double,因此唯一考虑的重载是在foo调用之前声明的重载.奇怪的MSVC行为似乎是非标准的.


Die*_*ühl 3

以下是标准对此的规定。首先,在 8.3.6 [dcl.fct.default] 第 5 段中:

...默认参数中的名称被绑定,并在默认参数出现的位置检查语义约束。函数模板和类模板的成员函数中默认参数的名称查找和语义约束检查按照 14.7.1 中的描述执行。...

进一步在 14.7.1 [temp.inst] 第 12 段中:

如果以需要使用默认参数的方式调用函数模板 f,则将查找依赖名称,检查语义约束,并像默认参数一样完成默认参数中使用的任何模板的实例化是在函数模板特化中使用的初始化程序,与当时使用的函数模板 f 具有相同的作用域、相同的模板参数和相同的访问权限。这种分析称为默认参数实例化。然后将实例化的默认参数用作 f 的参数。

我不太确定这到底说了什么。我可以在本文中看到两种解释。如果重要的话,我认为 EDG 同意 gcc 和 clang。