1

摘自本书 - C++ 模板:David, Nicolai 的完整指南

因此,模板被编译两次:

  1. 在没有实例化的情况下,将检查模板代码本身的语法是否正确。发现语法错误,例如缺少分号。
  2. 在实例化时,会检查模板代码以确保所有调用都有效。发现无效调用,例如不支持的函数调用。

保持第一点,我写道 -

template<typename T>
void foo( T x)
{
   some illegal text
}

int main()
{
   return 0;
}

它在 Visual Studio 2010 上构建良好,没有任何警告关闭优化。但是,它在 gcc-4.3.4 上失败了。哪一个符合 C++ 标准?即使没有模板实例化,模板代码是否也必须编译?

4

2 回答 2

7

有问题的程序格式错误,但 C++ 标准在这种情况下不需要诊断,因此 Visual Studio 和 GCC 都以兼容的方式运行。来自 C++03 标准的第 14.6/7 节(强调我的):

知道哪些名称是类型名称可以检查每个模板定义的语法。对于可以生成有效特化的模板定义,不应发出诊断。如果无法为模板定义生成有效的特化,并且该模板未实例化,则模板定义格式错误,无需诊断。如果在非依赖名称中使用的类型在定义模板时是不完整的,但在实例化完成时是完整的,并且如果该类型的完整性影响程序是否良好 -形成或影响程序的语义,程序是非良构的;不需要诊断。[注:如果模板被实例化,错误将根据本标准中的其他规则进行诊断。准确诊断这些错误的时间是实施质量问题。] [示例:

int j;
template<class T> class X {
    // ...
    void f(T t, int i, char* p)
    {
        t = i; // diagnosed if X::f is instantiated
               // and the assignment to t is an error
        p = i; // may be diagnosed even if X::f is
               // not instantiated
        p = j; // may be diagnosed even if X::f is
               // not instantiated
    }
    void g(T t) {
        +; //may be diagnosed even if X::g is
           // not instantiated
    }
};

—<em>结束示例]

于 2012-04-25T21:41:28.070 回答
0

您正在看的这本书似乎(主要)反映了作者对编译器实际工作方式的观察,而不是标准的要求。该标准并没有对模板中的格式错误的代码给予额外的宽大处理,只是因为它没有被实例化。

同时,这本书是正确的,编译器在实例化之前确实无法做太多检查。例如,您可以使用从属名称作为函数的名称(或者像函数一样调用它,无论如何——如果它是仿函数,那也可以)。如果您在作为函数的类上实例化该模板,那很好。如果你在一个真正是 的类上实例化它,那么int尝试调用它无疑会失败。在您实例化它之前,编译器无法分辨哪个是哪个。

concepts这是真正打算添加到 C++ 中的大部分内容。您可以直接指定(例如)模板 X 将T::y像函数一样调用。然后编译器可以将模板的内容与概念中的声明进行比较,并确定模板的主体是否与概念中的声明相匹配。在另一个方向上,编译器只需将一个类(或其他)与概念进行比较,以确定实例化该模板是否有效。如果它不起作用,它可以直接将错误报告为违反相关概念(就像现在一样,它会尝试实例化模板,并且您经常会收到一些奇怪的错误消息,表明真正的问题很糟糕,如果有的话)。

于 2012-04-25T21:38:15.767 回答