c++ - 为什么这个模板函数没有按预期运行?

标签 c++ function-templates name-lookup dependent-name unqualified-name

我正在阅读有关模板函数的内容,并对这个问题感到困惑:

#include <iostream>

void f(int) {
    std::cout << "f(int)\n";
}

template<typename T>
void g(T val) {
    std::cout << typeid(val).name() << "  ";
    f(val);
}

void f(double) {
    std::cout << "f(double)\n";
}

template void g<double>(double);

int main() {
    f(1.0); // f(double)
    f(1);   // f(int)
    g(1.0); // d  f(int), this is surprising
    g(1);   // i  f(int)
}

如果我不写template void g<double>(double);,结果是一样的.

我认为g<double>应该在 f(double) 之后实例化,因此调用 fg应该打电话f(double) 。令人惊讶的是,它仍然调用 f(int)g<double> 。谁能帮我理解这个?

<小时/>

读完答案后,我明白了我的困惑到底是什么。

这是一个更新的示例。除了我添加了 g<double> 的特化之外,它基本上没有变化。 :

#include <iostream>

void f(int){cout << "f(int)" << endl;}

template<typename T>
void g(T val)
{
    cout << typeid(val).name() << "  ";
    f(val);
}

void f(double){cout << "f(double)" << endl;}

//Now use user specialization to replace
//template void g<double>(double);

template<>
void g<double>(double val)
{
    cout << typeid(val).name() << "  ";
    f(val);
}

int main() {
    f(1.0); // f(double)
    f(1);  // f(int)
    g(1.0); // now d  f(double)
    g(1);  // i  f(int)
}

随着用户特化,g(1.0)表现如我所料。

编译器是否应该自动对 g<double> 进行相同的实例化?在同一个地方(或者甚至在 main() 之后,如 The C++ Programming Language 第 26.3.3 节所述,第四版)?

最佳答案

名称f是一个从属名称(它通过参数val依赖于T),它将被解析为two steps :

  1. Non-ADL lookup examines function declarations ... that are visible from the template definition context.
  2. ADL examines function declarations ... that are visible from either the template definition context or the template instantiation context.

void f(double) 从模板定义上下文中不可见,ADL 也找不到它,because

For arguments of fundamental type, the associated set of namespaces and classes is empty

<小时/>

我们可以稍微修改您的示例:

struct Int {};
struct Double : Int {};

void f(Int) { 
    std::cout << "f(Int)";
}

template<typename T>
void g(T val) {
    std::cout << typeid(val).name() << ' ';
    f(val);
    // (f)(val);
}

void f(Double) { 
    std::cout << "f(Double)";
}

int main() {
    g(Double{});
}

现在 ADL 将在第二步中找到 void f(Double),输出将为 6Double f(Double)。我们可以通过编写 (f)(val) (或 ::f(val))而不是 f(val) 来禁用 ADL。那么输出将为 6Double f(Int),与您的示例一致。

关于c++ - 为什么这个模板函数没有按预期运行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59099466/

相关文章:

c++ - 调用exit时使用vector,c++不清楚内存泄漏

c++ - 保存 URI 主机名的容器

c++ - 如何在模板函数中使用不同的结构作为模板参数?

c++ - 来自 iso C++ n3290 : Argument dependant Name Lookup: 的一个点

c++ - 模板特化的友元声明失败

c++ - poll() 不标记可读数据

c++ - 替代 map<someKey , map<anotherKey,Identifier >>

c++ - 模板参数类型取决于函数参数的模板函数

C++函数指针问题

c++ - 对基类成员数据的派生模板类访问