【问题标题】:C++: Compiler instantiate template function only on demand?C++:编译器仅按需实例化模板函数?
【发布时间】:2014-09-17 12:01:20
【问题描述】:

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

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 永远不会被实例化。但是,这不会编译...
由于没有提供模板参数,因此该模板函数据称对编译器没有任何意义(这是一个简单的比较函数,但请考虑一个严重依赖于模板参数类型的模板函数......)
那么究竟什么是“实例化”呢?

【问题讨论】:

  • 在您的第一段中:当您的老师说“显式”时,他的意思不是“演绎”。模板类型推导知道T是什么的隐式方法。 (换句话说,不存在显式模板类型推导。)
  • 对不起,正确的短语是“指定,无论是隐含的还是明确的”......我会更正主帖。
  • 如果将x 替换为lhs,则代码会编译。
  • 如果你使用&lt;string&gt;,你也不需要string("blah")
  • @NeilKirk,我知道,这是为了演示目的...... :)

标签: c++ templates


【解决方案1】:

当编译器看到您的模板时,它已经在某种程度上对其进行了解析和分析。已经完成的工作非常复杂,但除此之外,(与模板参数无关)name lookup 发生了。这意味着编译器已经尝试找出 x 是什么,但他失败了。

编译器试图解决的一个例子是T::x 究竟是什么,因为它取决于 T,您的模板参数。 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 编写一个实例化失败的模板,但这超出了该问题的答案范围。

【讨论】:

  • 我相信标准术语称之为“名称查找”。
  • @T.C.谢谢。我从来不知道这些措辞。 :)
【解决方案2】:

§ 14.6 [temp.res]/p10,添加重点:

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

如果不能为模板生成有效的特化,则模板格式错误的一般规则不同,违反此规则需要诊断(因为它没有“不需要诊断”)。

在您的代码中,x 是一个非依赖名称,因此compare 模板违反了此规则,并且需要符合要求的实现来生成诊断。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 2017-06-19
    • 1970-01-01
    • 2015-01-16
    • 2013-03-31
    • 2011-10-07
    • 1970-01-01
    • 2011-11-03
    相关资源
    最近更新 更多