我正在尝试将我自己的lib从Visual Studio移植到GNU / Linux上的g ++,并且我在模板编译时遇到了一些问题。实际上,在Visual C ++中,只有在代码中明确使用模板时才会生成模板,而看起来(根据我的错误)g ++在首次使用模板之前会对模板的内容进行评估。这会导致以下错误:
error: incomplete type ‘X’ used in nested name specifier
...因为我在模板代码之后包含了一些类,而不是之前。我这样做是因为交叉使用冲突。
总之,似乎Visual C ++不会尝试在使用时解析模板的内容,而g ++会尽快解析。
class MyClass;
template<class _Ty>
void func(MyClass* a_pArg)
{
a_pArg->foo();
};
(_ Ty未使用,但无关紧要,只是为了解释问题)
在这种情况下,Visual C ++将编译(即使MyClass
未预先声明),而g ++不会,因为MyClass
尚未完全声明。
有没有办法告诉g ++仅在使用时实例化模板?
答案 0 :(得分:9)
不,这就是两阶段查找的工作方式。 MSVC实现它错误,它几乎跳过了第一阶段,它在定义点解析模板。 MSVC仅在此处执行一些基本语法检查。在第二阶段,在实际使用模板时,只应检查从属名称。 MSVC在这里进行所有类型的解析。 GCC正确实现了两阶段查找。
在您的情况下,由于MyClass
不是模板参数,因此可以在第一阶段检查它。您只需要 来包含您的类标题。
答案 1 :(得分:1)
正如另一个答案所示,gcc在第一个查找阶段查找非依赖名称是正确的,VC ++将大多数检查转移到第二阶段(这是不正确的)。为了修复你的代码,你不需要搜索一些破解版的gcc。您需要将声明和实现分开(至少对于非依赖名称)。使用您的示例,
// provide declarations
class MyClass;
template<class T>
void func(MyClass* a_pArg);
// provide definition of MyClass
class MyClass
{
// watever
};
// provide definition of func
template<class T>
void func(MyClass* a_pArg);
{
a_pArg->foo();
};
答案 2 :(得分:1)
如果您愿意使用CLang而不是gcc,CLang支持-fdelayed-template
(专用于在解析结束时执行模板实例化),-fms-extensions
选项隐含专门用于编译MSVC代码(和许多怪癖。)
根据Francois Pichet的说法,他正在领导CLang全力编译MSVC代码(并且实际上正在完成大部分代码),CLang应该能够在大约2到3个月内解析所有MFC代码,只有几个非仍然存在重大问题。已经正确解释了大多数MFC(即,解释为VC ++)。
答案 3 :(得分:0)
Visual C ++默认情况下不会实现标准指定的两阶段查找。
但是,在使用/ Za选项的Visual Studio 2015中,看起来两阶段查找会更好一些。也许您可以通过添加/ Za选项来模拟GCC模板实例化行为,以便在某些情况下执行相反的操作。