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

时间:2012-11-21 00:00:27

标签: 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;
}

我希望这个程序输出

foo(int)
foo(double)

对应于foo的两个重载,这些重载在bar实例化时可见。

相反,使用g++-4.6编译时,输出为

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

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

3 个答案:

答案 0 :(得分: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;
}

使用g++-4.6编译时,此程序输出:

$ g++ test_2.cpp ; ./a.out 
foo(type1)
foo(type2)

换句话说,foo在实例化时通过ADL解析{/ 1}}。

来自OP的代码的行为似乎是ADL不适用于barint等基元,因此所考虑的唯一重载是double之前声明的重载。的电话。奇怪的MSVC行为似乎是非标准的。

答案 1 :(得分:3)

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

  

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

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

  

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

的参数

我不太清楚这究竟是什么意思。我可以在本文中看到这两种解释。如果它很重要,我认为EDG同意gcc和clang。

答案 2 :(得分:1)

也许是因为你在模板之后声明并且已经定义了重载函数“foo(double)”,所以它对它的存在一无所知。 - &gt;结构化编程。 我建议:

#include <iostream>

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

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

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



int main()
{
bar<int>(1);
bar<double>(1);
return 0; 
}