Shi*_*rik 5 c++ gcc visual-studio
将代码从Visual Studio移植到gcc时,我发现了一个奇怪的问题.以下代码在Visual Studio中编译良好,但导致gcc中出错.
namespace Baz
{
template <class T>
class Foo
{
public:
void Bar()
{
Baz::Print();
}
};
void Print() { std::cout << "Hello, world!" << std::endl; }
}
int main()
{
Baz::Foo<int> foo;
foo.Bar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我的理解是这应该编译好,因为在实例化模板之前不应该编译类(在定义了Print()之后).但是,gcc报告如下:
t.cpp:在成员函数'void Baz :: Foo :: Bar()'中:第8行:错误:'Print'不是'Baz'的成员
谁是对的?如果gcc是对的,为什么?
gcc是对的.模板分两个阶段编译:一次解析时,一次实例化.
在分析时,会检查不依赖于模板参数的任何内容,因此在这种情况下会Baz::Print被查找,并且发现没有声明,所以这是一个错误.
如果调用已经T().Print()或依赖于类型的其他东西,T那么查找将被延迟直到实例化时间(或者至少部分延迟---见下文).
除非资格本身依赖于模板参数(例如T::Print),否则Baz :: Print等合格的名称总是在定义时查找,尽管重载决策被推迟到实例化时间.这意味着在声明模板后,您无法添加限定名称的重载集.
Print如果任何函数参数依赖于模板参数,则会在实例化时查找非限定名称(例如just).所以Print(T())会在实例化时查看,而Baz::Print(T())不是.值得注意的是,实例化时间查找仅限于在声明点处可见的名称和通过ADL找到的名称,因此Foo<int>,即使是普通Print(T())也不应该找到Baz::Print它是否在模板之后声明(如示例中所示).
要使示例代码有效,可以在定义Foo<T>::Bar之后定义,也可以在定义之前定义前Print向声明.PrintFoo
海湾合作委员会是对的。这是因为Baz是一个命名空间,并且命名空间是从上到下解析的,因此 的声明Baz::Print从内部不可见Foo(因为它位于其下方)。
实例化模板时,仅考虑模板定义中可见的名称,不计算 Koenig 查找(这不会改变您的情况)。
如果Baz是一个结构或类,您的代码将起作用,因为它们分两个阶段进行解析(首先是声明,然后是主体),因此在结构或类中声明的任何内容在例如内部都是可见的。成员函数,无论它们在源文件中的顺序如何。
Baz::Print您可以通过在 before声明来使其工作Foo。
引用标准:
模板定义中使用的非依赖名称是使用通常的名称查找找到的,并在使用它们时绑定。
在解析从属名称时,会考虑以下来源的名称:
(报价结束)
当Print是非依赖的(就像现在一样)时,不会找到它,因为它是在其声明之前(在模板定义上下文中)查找的。如果它是依赖的,则它不会是第一种情况(与非依赖时相同),并且Baz不以任何方式与 int (模板参数)关联,因此也不会根据第二种情况进行搜索。
| 归档时间: |
|
| 查看次数: |
334 次 |
| 最近记录: |