【问题标题】:What does it mean to "ODR-use" something?“使用 ODR” 是什么意思?
【发布时间】:2013-11-06 23:25:15
【问题描述】:

这只是在another question 的上下文中出现的。

显然,类模板中的成员函数只有在使用 ODR 时才会被实例化。 有人可以解释这到底是什么意思。 wikipedia article on One Definition Rule (ODR) 没有提到“ODR-use”。

然而标准将其定义为

名称显示为潜在求值表达式的变量 是 odr-used 除非它是满足要求的对象 出现在常量表达式 (5.19) 和左值到右值 立即应用转换 (4.1)。

在 [basic.def.odr] 中。

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

一个非重载函数,其名称显示为 潜在评估的表达式或一组候选者的成员 函数,如果在从一个引用时通过重载决议选择 可能求值的表达式,是 odr 使用的,除非它是纯粹的 虚函数及其名称没有明确限定。

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

【问题讨论】:

  • 注意[basic.def.odr]/6适用于类模板的成员函数“可以有多个定义[...]”
  • “如果我显式实例化一个类模板,是否所有成员函数都实例化了?” 是的,参见 [temp.explicit]/8+9

标签: c++ templates one-definition-rule


【解决方案1】:

这只是一个任意定义,标准用于 指定何时必须为实体提供定义(如 反对只是一个声明)。标准不只是说 “使用”,因为这可以根据不同的情况进行不同的解释 语境。并且某些 ODR 使用并不真正对应于哪一个 通常会与“使用”相关联;例如,一个虚拟 函数总是被 ODR 使用,除非它是纯的,即使它不是 实际上在程序的任何地方调用。

完整的定义在§3.2,第二段,虽然这 包含对其他部分的引用以完成 定义。

关于模板,使用 ODR 只是问题的一部分; 另一部分是实例化。特别是,§14.7 涵盖 当模板被实例化时。但两者是相关的:while §14.7.1(隐式实例化)中的文本相当长, 基本原则是只有在以下情况下才会实例化模板 它被使用,在这种情况下,使用意味着 ODR 使用。因此, 类模板的成员函数只会被实例化 如果它被调用,或者它是虚拟的并且类本身是 实例化。标准本身在许多方面都依赖于此 地方:std::list<>::sort在个人上使用< 元素,但您可以在元素类型上实例化列表 不支持<,只要你不调用sort 它。

【讨论】:

  • ODR 使用是否与“物化临时”重叠?
【解决方案2】:

简单来说,odr-used 意味着某些东西(变量或函数)在必须存在其定义的上下文中使用。

例如,

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

注意,上面的 push_back 在 MSVC 2013 中通过,这种行为不符合标准,gcc 4.8.2 和 clang 3.8.0 都失败了,错误信息是: 未定义对F::g_x的引用

【讨论】:

  • 是否可以在 c++ 中使用像 vi.push_back( F::g_x ); 这样的静态数据成员?
  • 但是右值也可以传递给const int&amp;?静态 const 成员是否可以被视为右值?
  • +1 表示简洁的开头句:“简单来说,odr-used 意味着在必须存在定义的上下文中使用某些东西(变量或函数)。”
  • 我不明白您是如何编译该代码的。他们在同一个TU吗?如果是,F::g_x 在push_back 之前已经定义好了,当然会通过。不是吗?
  • @bigxiao"也可以传递一个右值" 是的,编译器会创建一个临时对象,并将引用绑定到该对象。 OTOH 传递左值时意味着传递左值评估所引用的对象:当您传递左值时,您可以期望函数中的参数引用正确的对象。编译器不会创建临时的。如果您想要一个临时的,请使用operator+
猜你喜欢
  • 1970-01-01
  • 2016-12-08
  • 1970-01-01
  • 2011-08-12
  • 2017-06-11
  • 2018-03-05
  • 2023-03-27
  • 2015-05-30
  • 2020-12-12
相关资源
最近更新 更多