13

考虑下面的函数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++ 标准中是否描述了这种情况?

4

3 回答 3

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 解析。bar

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

于 2012-11-21T00:57:05.097 回答
3

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

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

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

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

我不太确定这到底是什么意思。我可以在本文中看到这两种解释。万一这很重要,我认为 EDG 同意 gcc 和 clang。

于 2012-11-21T00:45:23.807 回答
1

可能是因为你在模板后面声明&定义了重载函数“foo(double)”,所以它不知道它的存在。->结构化编程。我建议:

#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; 
}
于 2012-11-21T00:48:40.217 回答