C ++:对函数重载和声明顺序的困惑

时间:2011-07-27 18:25:21

标签: c++ function overloading

我意识到C ++继承了C的许多要求,其中之一就是编译器不会识别全局函数,除非它以前遇到过这个函数的原型或定义。

这也会影响C ++函数重载。如果函数调用有多个候选者,如果编译器尚未看到它的原型/定义,则“正确”候选者将不会包含在选择过程中。

考虑:

void foo(int v)
{
    cout << "Int version" << endl;
}

template <class T>
void call_foo(const T& v)
{
    foo(v);
}

void foo(const std::string& v)
{
    cout << "Overload for string" << endl;
}

此处,对call_foo(std::string("abc"))的调用将导致编译器错误,即使foo的{​​{1}}超载也是如此。问题是函数模板std::string是在编译器看到重载之前定义的

但是,这似乎不适用于全局运算符重载。我们经常重载call_foo以使我们的自定义类型与C ++ ostreams兼容。无论定义了运算符重载函数,编译器都会选择正确的重载。

例如:

std::ostream& operator << (std::ostream& os, const T&);

在这里,如果我们调用struct Bar { }; template <class T> void dispatch(const T& v) { std::cout << v << std::endl; } std::ostream& operator << (std::ostream& os, const Bar& b) { os << "Outputting Bar..."; return os; } ,编译器会调用正确的重载并输出dispatch(Bar())

因此,在选择候选函数进行运算符重载时,似乎C ++标准允许更高级的行为。

我的问题是,为什么这种能力不能扩展到常规函数重载?我意识到需要向后兼容C,但这并不会对此产生任何影响,因为只要你编写一个函数重载,你就不会编写一个C程序。

1 个答案:

答案 0 :(得分:5)

首先,编译器无需查看定义 实践超载解决;声明就足够了。第二, 问题比你似乎意识到的要复杂得多。在你的功能 模板call_foofoo是一个从属名称,因为它用于 取决于实例化类型的上下文。这意味着它 将被查找两次,一次在模板的位置 定义,第二次实例化模板。这个 然而,第二次查找纯粹是ADL;它不会找到声明 由ADL引进。在您的情况下,您想要的foo是全局的 命名空间,但在使用std::string调用它时,唯一的命名空间 ADL考虑的是std::

在你的第二个例子中,Bar在全局命名空间中,所以声明在 将考虑实例化时的全局命名空间。 (请注意,如果dispatch不是模板,则不会 考虑。)