“ ODR 使用”是什么意思?

这是在 另一个问题中提到的。

显然,类模板中的成员函数只有在使用 ODR 时才被实例化。 有人能解释一下这到底是什么意思吗? 关于单一定义规则(ODR)的维基百科文章没有提到“ ODR 使用”。

然而,标准将其定义为

名称显示为可能计算的表达式的变量 是 用过的,除非它是一个对象,以满足 出现在常量表达式(5.19)和 lvalue-to-rvalue 中 立即应用转换(4.1)。

在[ basic.def.odr ]中。

编辑: 显然这是错误的部分,整个段落包含了对不同事物的多重定义。这可能与类模板成员函数有关:

名称显示为 可能求值的表达式或候选集的成员 函数,如果通过重载分辨率选择,则从 可能求值的表达式,除非它是纯的 虚函数及其名称没有显式限定。

但是我不明白,这个规则是如何在多个编译单元之间工作的?如果显式实例化类模板,是否所有成员函数都实例化了?

21325 次浏览

It's just an arbitrary definition, used by the standard to specify when you must provide a definition for an entity (as opposed to just a declaration). The standard doesn't say just "used", because this can be interpreted diversely depending on context. And some ODR-use doesn't really correspond to what one would normally associate with "use"; for example, a virtual function is always ODR-used unless it is pure, even if it isn't actually called anywhere in the program.

The full definition is in §3.2, second paragraph, although this contains references to other sections to complete the definition.

With regards to templates, ODR-used is only part of question; the other part is instantiation. In particular, §14.7 covers when a template is instantiated. But the two are related: while the text in §14.7.1 (implicit instantiation) is fairly long, the basic principle is that a template will only be instantiated if it is used, and in this context, used means ODR-used. Thus, a member function of a class template will only be instantiated if it is called, or if it is virtual and the class itself is instantiated. The standard itself counts on this in many places: the std::list<>::sort uses < on the individual elements, but you can instantiate a list over an element type which doesn't support <, as long as you don't call sort on it.

In plain word, odr-used means something(variable or function) is used in a context where the definition of it must be present.

e.g.,

struct F {
static const int g_x = 2;
};


int g_x_plus_1 = F::g_x + 1; // in this context, only the value of g_x is needed.
// so it's OK without the definition of g_x


vector<int>  vi;
vi.push_back( F::g_x );      // Error, this is odr-used, push_back(const int & t) expect
// a const lvalue, so it's definition must be present

Note, the above push_back passed in MSVC 2013. This behavior is not standard compliant - both gcc 4.8.2 and clang 3.8.0 failed, with error message: undefined reference to F::g_x