繁体   English   中英

C ++:函数重载和声明顺序混乱

[英]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::stringfoo的重载,对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_foofoo是一个从属名称,因为它在依赖于实例化类型的上下文中使用。 这意味着它将被查找两次,一次是在定义模板的点,另一次是模板的实例化。 但是,第二个查询纯粹是ADL。 它将找不到ADL不带的声明。 在您的情况下,所需的foo在全局命名空间中,但是当使用std::string调用它时,ADL唯一考虑的命名空间是std::

在第二个示例中, Bar在全局名称空间中,因此将在实例化点考虑全局名称空间中的声明。 (请注意,如果dispatch不是模板,则不会考虑。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM