gpt4 book ai didi

c++ - 重载解析解析为一个尚不可见的函数

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:11:42 25 4
gpt4 key购买 nike

这是 this 的后续题。

#include <iostream>

struct type1 {};
struct type2 {};

void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}

template<typename T>
void bar() {
foo(T());
}

int main()
{
bar<type1>();
bar<type2>();
return 0;
}

void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}

在上面的代码中foo(type2)bar<type2> 的实例化时不可见在 main .然而代码编译并产生以下输出:

foo(type1)
foo(type2)

编译器如何知道 foo(type2)实例化时可用 bar<type2>main

编辑:我试图更多地了解模板实例化过程中的重载解析是如何工作的。考虑下面的代码:

#include <iostream>

struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};

void foo(type1 x)
{
std::cout << "foo(type1)" << std::endl;
}

void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}

int main()
{
foo(type3());
return 0;
}

void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}

输出是

foo(type2)

即使是更接近的比赛foo(type3)有空,电话foo(type3())解析为 foo(type2)因为在那之前,这是唯一被编译器解析过的候选者。现在考虑以下代码:

#include <iostream>

struct type1 {};
struct type2 {};
struct type3 {
operator type2() { return type2(); }
};

void foo(type2 x)
{
std::cout << "foo(type2)" << std::endl;
}

template<typename T>
void bar() {
foo(T());
}

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

void foo(type3 x)
{
std::cout << "foo(type3)" << std::endl;
}

输出是

foo(type3)

也就是调用点bar<type3>() , 即使只有 foo(type2)可见,编译器仍然选择 foo(type3)稍后出现,因为这是更接近的匹配。

最佳答案

任何没有定义的符号都将在链接过程中被替换,因为函数 foo(type2)可以在另一个文件中提供。

编译器会在整个过程结束时说出所需的函数是否已定义,此时无法应用进一步的替换。

为了阐明理解,您必须了解编译(例如,一个普通的 C 程序)所需的步骤:

  • 首先,展开代码中的所有宏;

  • 然后根据语言语法验证您的代码,以便将其转换为汇编语言——编译过程本身;在此步骤中,找到的每个没有定义的符号都会在表中用条目 (symbol, definition) 进行注释, 稍后将完成,以便正确构建您的程序;

  • 接下来,您编译成汇编的代码将被转换为机器语言,即创建对象;

  • 最后,您需要链接您已经可执行的对象,以解决对符号定义的任何依赖;最后一步检查您的对象是否有 undefined symbol ,添加来自其他模块或库的定义,从而完成程序。

如果任何符号没有正确“链接”到它的定义,编译器将指出程序中的错误——经典的 undefined reference to... .

考虑到您发布的代码,该过程将一直执行到它到达编译器为止。编译器会遍历代码,注意 type1 的定义, type2 , foo(type1 x) , 和 bar<T>() .

struct type1 {};
struct type2 {};

当它到达 main 时,它会找到对 bar<type1>(); 的调用, 并会调用 foo(type1()) ,这是已知的,可以正确使用。

void foo(type1 x) {
std::cout << "foo(type1)" << std::endl;
}

template<typename T>
void bar() {
foo(T());
}

int main() {

bar<type1>();
bar<type2>();
return 0;

}

一旦到达下一个电话,bar<type2>(); , 它会尝试调用 foo(type2()) , 但没有这样的定义可供使用,因此它将此调用关联为未知符号,必须在以后的过程中用定义替换。

编译器运行完main之后,它达到了一个新的定义,这正是正在创建的“翻译表”上缺少定义的定义。

void foo(type2 x) {
std::cout << "foo(type2)" << std::endl;
}

因此,在下一步中,编译能够用其各自的定义替换符号,并且程序可以正确编译。

问候!

关于c++ - 重载解析解析为一个尚不可见的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13485132/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com