代码之家  ›  专栏  ›  技术社区  ›  so.very.tired

C++:编译器仅按需实例化模板函数?

  •  2
  • so.very.tired  · 技术社区  · 10 年前

    考虑以下简单的模板函数:

    template <typename T>
    int compare(const T& lhs, const T& rhs) {
        if (lhs<rhs) {
            return -1;
        }
        else if (rhs<lhs) {
            return 1;
        }
        else {
            return 0;
        }
    }
    

    我的课程讲师解释说,当我们使用模板函数时,我们应该隐式或显式地指定要绑定到模板参数的模板参数:

    #include<iostream>
    #include<string>
    using std::cout;
    using std::endl;
    using std::string;
    
    int main() {
        // implicitly specifying that T is int
        cout<<compare(2,3)<<endl;
    
        // explicitly specifying that T is string
        cout<<compare<string>(string("something"),string("another"))<<endl;
    }
    

    这个推导正确模板的过程称为“实例化”;实际的模板参数用于生成稍后在运行时运行的适当版本的特定实例(在本例中是一个函数)。
    他还提到实例化是“按需”发生的;例如,最后一个代码段将生成比较函数的两个实例,一个用于 int 一个用于 string .
    这让我感到奇怪,为什么编译器会抱怨这样的事情:

    #include<iostream>
    #include<string>
    using std::cout;
    using std::endl;
    using std::string;
    
    
    template <typename T>
    int compare(const T& lhs, const T& rhs) {
        if (lhs<rhs) {
            return x; // deliberate compile-time error; x cannot be resolved
        }
        else if (rhs<lhs) {
            return 1;
        }
        else {
            return 0;
        }
    }
    
    int main() {
        // no calls for compare are made here
    }
    

    您可能会认为编译器不应该有上述编译时错误的任何问题,因为compare从未实例化过。但是,这不会编译。。。
    由于没有提供模板参数,因此该模板函数据称对编译器没有任何意义(这是一个简单的比较函数,但请考虑一个严重依赖于模板参数类型的模板函数…)
    那么“实例化”到底是什么呢?

    2 回复  |  直到 10 年前
        1
  •  5
  •   leemes    10 年前

    当编译器看到您的模板时,它已经解析并分析了它 在某种程度上 。确切地说,已经完成的工作相当复杂,但除此之外,(模板参数无关) 名字查找 发生。这意味着编译器已经尝试找出 x 是的,他失败了。

    编译器所做的示例 试图解决的问题 T::x 是,因为它 取决于 在…上 T ,模板参数。表达式 x(x) 不依赖于 对于任何模板参数,这基本上就是关键区别 x(x) 未能编译和 T: :x will succeed :

    template <typename T>
    int compare(const T& lhs, const T& rhs) {
        if (lhs<rhs) {
            return T::x;
        }
        else if (rhs<lhs) {
            return 1;
        }
        else {
            return 0;
        }
    }
    

    当然,对于大多数类型 T 这将失败 被实例化 但这不是关键。您甚至可以编写实例化失败的模板 T ,但这超出了回答这个问题的范围。

        2
  •  1
  •   T.C. Yksisarvinen    10 年前

    §14.6【临时要求】/p10,增加强调:

    如果名称不依赖于 模板参数 (定义见 14.6.2), 该名称的声明(或一组声明)应在模板中出现该名称时的范围内 释义 ; 名称绑定到声明(或多个声明) 并且该绑定不受声明的影响 在实例化时可见。

    与一般规则不同,如果无法为模板生成有效的专用化,则模板格式不正确,违反此规则需要进行诊断(因为它没有“不需要诊断”)。

    在您的代码中, x 是非从属名称,因此 compare 模板违反了这一规则,需要一致的实现来生成诊断。