[英]C++: Confusion over function overloading and order of declaration
我意识到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;
}
在这里,即使std::string
有foo
的重载,对call_foo(std::string("abc"))
的调用也会导致编译器错误 。 问题在于,在编译器看到重载之前 call_foo
定义了函数模板call_foo
。
但是,这似乎不适用于全局运算符重载 。 我们定期重载std::ostream& operator << (std::ostream& os, const T&);
使我们的自定义类型与C ++ ostream兼容。 无论在何处定义运算符重载函数,编译器都会选择正确的重载。
例如:
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())
,则编译器将调用正确的重载并输出Outputting Bar...
因此,当选择用于运算符重载的候选函数时,C ++标准似乎允许更高级的行为。
我的问题是,为什么不将此功能扩展到常规函数重载? 我意识到有向后兼容C的要求,但这实际上并没有任何关系,因为一旦编写函数重载,您就不会在编写C程序。
首先,编译器在执行重载解析时无需查看定义。 声明就足够了。 第二,这个问题比您想象的要复杂得多。 在函数模板call_foo
, foo
是一个从属名称,因为它在依赖于实例化类型的上下文中使用。 这意味着它将被查找两次,一次是在定义模板的点,另一次是模板的实例化。 但是,第二个查询纯粹是ADL。 它将找不到ADL不带的声明。 在您的情况下,所需的foo
在全局命名空间中,但是当使用std::string
调用它时,ADL唯一考虑的命名空间是std::
。
在第二个示例中, Bar
在全局名称空间中,因此将在实例化点考虑全局名称空间中的声明。 (请注意,如果dispatch
不是模板,则不会考虑。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.