c++ - 编译器检查未实例化的模板代码是什么?

标签 c++ templates gcc clang language-lawyer

例如,以下代码段使用 gcc-4.9 和 clang-602 编译

class Base                                                                      
{                                                                               
public:                                                                         
    static void foo() {}                                                        
    void badfoo(int i) {}                                                       
};                                                                              

template <typename T>                                                           
class Derived : public Base                                                     
{                                                                               
public:                                                                         
    void bar() { Base::foo(); }                                                 
    void badbar() { Base::badfoo(); }  // compiles ok
    //static void badbar() { Base::badfoo(); }  // compile error                                                                                    
    //void worsebar() { Base::nonexist(); }  // compile error                                   
};                                                                              

int main()                                                                      
{                                                                               
    return 0;                                                                   
}  

但是注释掉的行不会编译。

我的问题是:

  1. 为什么 badbar() 可以编译,而 worsebar() 不能?

  2. 如果我将 badbar() 更改为静态,它也不会编译,无论 base::badfoo 是否为静态。

  3. 标准是否说明了在这种情况下应该检查什么? gcc4.4居然连badbar()都拒绝编译。

更新:

许多答案已经解释了问题 1,但似乎编译器有时也会加倍努力检查过载,它发生在 gcc 4.4.3 和 4.8.2 上,但不是 4.7.2 和 4.9.1 .

问题 2:正如 Marco A. 指出的那样,clang 不会编译,但 gcc4.9 仍然可以通过。但是,gcc4.2 和 gcc4.4 都拒绝了代码,他们提示的错误是“没有匹配的函数”而不是“在没有对象的情况下调用非静态成员”。这个问题似乎没有确凿的答案,所以我按照 Daniel Frey 的建议添加了语言律师标签。

更多更新:

我认为问题 2 的答案现在非常明确:添加静态声明是否会改变诊断取决于编译器。它因编译器和同一编译器的不同版本而异。语言律师没有出现,我将接受 Daniel Frey 的回答,因为它最好地解释了第一个问题。但 Marco A. 和 Hadi Brais 的回答也值得一读。

最佳答案

该标准只要求名称查找发生在第 1 阶段,即第一次解析模板时。这会在 badbar 中出现 badfoo,这就是代码编译的原因。那时编译器不需要做重载决议。

badbar 被实例化时,重载解析(总是作为一个单独的步骤名称查找之后发生)然后在第 2 阶段执行 - 这在你的例子。这个原则可以在

中找到

3.4 Name lookup [basic.lookup]

1 The name lookup rules apply uniformly to all names (including typedef-names (7.1.3), namespace-names (7.3), and class-names (9.1)) wherever the grammar allows such names in the context discussed by a particular rule. Name lookup associates the use of a name with a declaration (3.1) of that name. Name lookup shall find an unambiguous declaration for the name (see 10.2). Name lookup may associate more than one declaration with a name if it finds the name to be a function name; the declarations are said to form a set of overloaded functions (13.1). Overload resolution (13.3) takes place after name lookup has succeeded. The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded. Only after name lookup, function overload resolution (if applicable) and access checking have succeeded are the attributes introduced by the name’s declaration used further in expression processing (Clause 5).

(强调我的)

因此,我会说编译器可以正确接受代码,尽管我不确定他们是否需要这样做。

查看代码being rejected ,你需要实例化badbar

关于c++ - 编译器检查未实例化的模板代码是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30232485/

相关文章:

C++返回具有最小硬币的数组/vector 以获取值(value)动态规划

c++ - g++ 使用 -Wpedantic 选项 : Is there an option to disable only the warning about unnamed structs? 编译 C++11

c - __builtin_apply 用于在 gcc 中构造调用的大小参数?

wpf - WPF和Powershell,需要知道如何向控件元素添加样式

c++ - 为什么这个循环模板实例化是合法的?

c - 优化函数进入/退出 (gcc)

c++ - 为什么编译器让我调用 pow 和 sqrt,即使我没有包含 cmath?

c++ - Visual Studio 如何在内核模式驱动程序项目中使用 C++ 标准库?

c++ - 是否可以将 double 数组转换为 char *?

email - 在 http res 上下文之外劫持 expressjs View 引擎