【问题标题】:Are C++ templates be checked for syntax errors without instantiating them?是否在不实例化它们的情况下检查 C++ 模板的语法错误?
【发布时间】:2016-06-09 16:20:56
【问题描述】:

如果 C++ 模板包含明显的类型错误,例如对不存在的类成员的引用,语言标准是否保证在定义模板时检测到错误?

还是保证只有在模板实例化时才能检测到错误?

  1. 假设错误不涉及任何模板参数?

  2. 假设它确实涉及模板参数之一?

【问题讨论】:

  • 如何在不指定参数类型的情况下检查参数类型(即实例化模板)?也许我不明白你的问题,但当然有可能检查模板参数的约束,但你需要有具体的类型才能这样做。因此,您的第三点充其量描述了 IMO 的行为。
  • 不清楚你在问什么。 类型检查模板是什么意思?模板参数替换?
  • @Drop OP 显然意味着约束检查(又名概念)。
  • 模板有两个阶段,一个用于不依赖模板的东西,另一个用于依赖模板的东西。 (视觉不尊重,顺便说一句)。
  • @Drop 好的,我至少不确定这是否明显。问题不清楚。给出一个带有模板的小代码示例至少是一种很好的风格,并且询问哪些部分将被检查将由编译器在不实例化的情况下检查。

标签: c++ templates typechecking definition-checking


【解决方案1】:

检查是允许的,但不是必需的。 [temp.res]/8:

知道哪些名称是类型名称允许每个模板的语法 被检查。该程序格式错误,不需要诊断,如果:

  • 无法为模板生成有效的特化并且该模板未实例化,或者

  • 可变参数模板的每个有效特化都需要一个空模板参数包,或者

  • 紧随其定义的模板的假设实例化由于不依赖的构造而格式错误 在模板参数上,或

  • 在假设的实例化中对这种构造的解释不同于对 模板的任何实际实例化中的相应构造。

请注意,两阶段查找实际上不需要提前检查:需要在模板定义上下文中完成各种名称查找,但实际上并不要求在定义时完成。

【讨论】:

    【解决方案2】:

    至于你的(原始)标题

    可以在不实例化的情况下对 C++ 模板进行类型检查吗?

    取决于 typecheck 的确切含义。


    语言标准是否保证在定义模板时检测到错误?

    关于模板声明(!)和定义本身,将在实例化之前检查语法正确性,正如您在问题中提到的那样。

    已经完成了一些类型检查 ...

    template<typename T>
    class Foo {
         Foo() : x(y) {}
    private:
         int &x;
         T z;
    };
    
    int main() {
    } 
    

    clang =============
    main.cpp:4:20: error: use of undeclared identifier 'y'
             Foo() : x(y) {}
                       ^
    1 error generated.
    gcc =============
    main.cpp: In constructor 'Foo<T>::Foo()':
    main.cpp:4:20: error: 'y' was not declared in this scope
              Foo() : x(y) {}
                        ^
    

    Demo


    ...但与

    不一致
    template<typename T>
    class Foo {
         Foo() : x(Foo::y) {}
    private:
         int &x;
         T z;
    };
    
    int main() {
    }
    

    clang =============
    main.cpp:4:25: error: no member named 'y' in 'Foo<T>'
             Foo() : x(Foo::y) {}
                       ~~~~~^
    1 error generated.
    gcc =============
    

    Demo


    Foo 被实际实例化时,GCC 也会抛出错误:

    template<typename T>
    class Foo {
    public:
         Foo() : x(Foo::y) {}
    private:
         int &x;
         T z;
    };
    
    int main() {
        Foo<int> foo; // <<<<<<<<<<<<<<<<<<<<<
    }
    

    clang =============
    main.cpp:5:25: error: no member named 'y' in 'Foo<T>'
             Foo() : x(Foo::y) {}
                       ~~~~~^
    1 error generated.
    gcc =============
    main.cpp: In instantiation of 'Foo<T>::Foo() [with T = int]':
    main.cpp:12:18:   required from here
    main.cpp:5:26: error: 'y' is not a member of 'Foo<int>'
              Foo() : x(Foo::y) {}
                              ^
    

    Demo

    还是保证只有在模板实例化时才能检测到错误?

    所以这似乎是真的。


    这似乎是编译器实现的具体细节。
    所以不,显然没有标准的保证。

    正如@Jarod42 在他们的Clang/GCC sample 中显示的那样

    template <typename T>
    void foo()
    {
        int a = "hello world";
        const char* hello = 42;
    }
    
    int main()
    {
    }
    

    clang =============
    main.cpp:6:9: error: cannot initialize a variable of type 'int' with an lvalue of type 'const char [12]'
        int a = "hello world";
            ^   ~~~~~~~~~~~~~
    main.cpp:7:17: error: cannot initialize a variable of type 'const char *' with an rvalue of type 'int'
        const char* hello = 42;
                    ^       ~~
    2 errors generated.
    gcc =============
    

    所以恐怕没有什么比c++ standard specification 的第 14.5 节更可用的了,这被认为是有效的模板声明/定义语法。



    关于您问题的以前版本:

    我想知道在模板实例化之前,模板定义可以进行多少类型检查。

    编译器需要查看具体的参数类型(和非类型参数值)以应用(并反过来实例化)这些类型的约束检查模板。

    所以模板必须被实例化才能做到这一点。


    • 可能模板很像 Lisp 中的宏:编译器会检查语法,但在模板实例化之前不会进行类型检查。并且每次实例化模板时,编译器都会再次运行类型检查器。

    这似乎是最接近的,虽然没有什么像在编译期间运行typechecker,但主要是实例化其他模板类并让std::static_assert最终决定,是否满足类型(或非类型)参数的约束。


    要了解 c++ 标准库如何处理这个问题,请参阅 Library Concepts


    【讨论】:

    • Clang 进行一些类型检查而不进行实例化(对于非模板依赖类型):Demo.
    • @Jarod42 我刚刚在写此评论时更新了我的答案。当然会检查模板声明和定义(不仅使用 clang IIRC)。这个问题确实不清楚。
    • 我的印象是“概念”仍然是一个实验性功能,还不是标准的一部分。有变化吗?
    • 我很惊讶 gcc 没有为给定的代码发出错误:-/
    • 顺便说一句,我写过 C 编译器。肯定有一个类型检查器在编译期间运行。例如,参见 Fraser 和 Hanson,A Retargetable C Compiler,从第 4 章开始的基础知识。
    猜你喜欢
    • 2022-06-27
    • 2020-06-19
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 2022-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多