4

我对以下示例的实例化点感到困惑:

#include <iostream>

void f(int){std::cout<<"int"<<std::endl;}//3

template <typename T>
void g(T t)
{
    f(t);//4
}

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

int main()
{
    g<int>(1);//1.point of instantiation for g<int>
    g<double>(1.1);//2.point of instantiation for g<double>, so f(double) is visible from here?
    return 0;
}

我虽然 f 是一个从属名称,而 1. 是 g< int > 的实例化点,而 2. 是 g< double > 的实例化点,所以 f(double) 对于 g(1.1) 是可见的,但是输出是

int
int

如果我在 3 处评论 f(int) 的声明,gcc 会报告错误(并不奇怪)并指出 4 处的 f(t) 是实例化点(惊讶!!)。

test.cpp: In instantiation of ‘void g(T) [with T = int]’:
test.cpp:16:10:   required from here
test.cpp:9:5: error: ‘f’ was not declared in this scope, and no    declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
  f(t);
     ^

任何人都可以为我清除实例化点和名称绑定的概念吗?

4

1 回答 1

9

f(t)是一个依赖的非限定函数调用表达式,因此只有在定义上下文中找到的函数和通过 ADL 找到的函数才是候选函数。f(int)在定义上下文中可见,但不可见f(double),因此重载决议f(int)对两个调用都解析为。

f(double)ADL 找不到,因为内置类型没有关联的类或命名空间。如果您传入了一个类类型的参数,并且f采用这种类型存在重载,ADL 将能够找到它。例如:

void f(int);

template <typename T>
void g(T t)
{
    f(t);
}

class A {};
void f(double);
void f(A);

int main()
{
    g(1);   // calls f(int)
    g(1.1); // calls f(int)
    g(A{}); // calls f(A)
}

f(A)被调用是因为它位于全局命名空间中,并且A的关联命名空间集是全局命名空间。

于 2015-05-28T18:34:43.243 回答