问题标签 [one-definition-rule]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
4 回答
1609 浏览

c++ - 如何在不指定类名的情况下专门化模板?

我想做一个函数debug,输出一些关于对象的信息。我的系统包含许多不同类型的对象;其中一些包含其他对象。

我希望函数输出name参数的成员(如果有的话),或者调试contents参数的成员(如果有的话)。我想出了以下代码:

在这里, 和 的代码pack几乎line相同!我想避免多次编写相同的代码:

但是这种语法与“简单”对象的函数模板冲突(具有相同的签名)。

我怎样才能重写我的代码?我不想重写第一部分(对 , 等的声明doghuman,因为我的程序的那部分已经非常复杂,并且只是为了调试而向其中添加东西(基类、成员函数等)似乎不合适。

0 投票
3 回答
2261 浏览

c++ - C ++:不同翻译单元中具有相同名称的不同类

考虑以下示例:

代码编译时没有任何编译器或链接器错误。但输出对我来说很奇怪:

  • Fedora x86_64 上的 gcc (Red Hat 4.6.1-9) 没有优化 [ EG1 ]:

    UsedClass 1 (0x7fff0be4a6ff) doit hit
    UsedClass 1 (0x7fff0be4a72e) doit hit

  • 与 [EG1] 相同,但启用了 -O2 选项 [ EG2 ]:

    UsedClass 2 (0x7fffcef79fcf) doit 命中
    UsedClass 1 (0x7fffcef79fff) doit 命中

  • Windows XP 32bit 上的 msvc2005 (14.00.50727.762) 没有优化 [ EG3 ]:

    UsedClass 1 (0012FF5B) doit 命中
    UsedClass 1 (0012FF67) doit 命中

  • 与 [EG3] 相同,但启用了 /O2(或 /Ox)[ EG4 ]:

    UsedClass 1 (0012FF73) doit 命中
    UsedClass 1 (0012FF7F) doit 命中

我期望链接器错误(假设违反了 ODR 规则)或 [EG2] 中的输出(内联代码,没有从翻译单元导出任何内容,保留 ODR 规则)。因此我的问题:

  1. 为什么输出 [EG1]、[EG3]、[EG4] 可能?
  2. 为什么我从不同的编译器甚至从同一个编译器得到不同的结果?这让我认为标准在这种情况下没有指定行为。

感谢您的任何建议、意见和标准解释。

更新
我想了解编译器的行为。更准确地说,如果违反了 ODR,为什么不会产生错误。一个假设是,由于UsedClass1UsedClass2类中的所有函数都被标记为内联(因此违反 C++03 3.2),因此链接器不会报告错误,但在这种情况下会输出 [EG1]、[EG3]、[ EG4] 看起来很奇怪。

0 投票
2 回答
948 浏览

c++ - 内联构造函数和一个定义规则

考虑以下源文件 1.cpp

2.cpp

从这些文件编译的程序是否格式正确?它的输出应该是什么?

由于违反单一定义规则或输出“1 2”,我预计链接器会出错。但是,当使用 g++ 3.4 和 VC 8.0 编译时,它会打印出“1 1”。
这怎么解释?

0 投票
2 回答
131 浏览

c++ - pg:172-176.PartA.Interface Design Alternatives, Stroustrup-CPL-3E

在第 172 页,Stroustrup 正在做这样的事情:

Q1。这是否意味着第一个命名空间被插入(例如)user.h 并包含在 main.cpp - 驱动程序中;第二个命名空间进入implementer.h 并包含在parse.cpp 中?这就是为什么他说:

“编译器没有足够的信息来检查命名空间的两个定义的一致性”

  • 因为implementer.h和user.h都不能包含在“Parser implementation”(parse.cpp)中?

172.png 173.png

在第 174 页,他有:

上层命名空间是否进入implementer.h,下层命名空间进入user.h

在他的“ dependency graph”中,他是否重申了显而易见的事实:当 Make 运行时,对“Parser”( parser.cpp/implementer.h) 的任何更改都会导致 driver/main.cpp 被重建——这是不必要的吗?

174.png

0 投票
4 回答
802 浏览

c++ - 如果我不使用变量,我可以在翻译单元中有多个定义吗?

该标准似乎暗示,如果不使用 odr(第 3.2/3 节),则对变量的定义数量没有限制:

每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的准确定义;无需诊断。

它确实说任何变量都不能在翻译单元中多次定义(第 3.2/1 节):

任何翻译单元都不得包含一个以上的任何变量、函数、类类型、枚举类型或模板的定义。

但是我在整个程序中找不到对非 ODR 使用的变量的限制。那么为什么我不能编译如下内容:

使用 g++ 4.6.3 编译和链接这些文件,我得到一个链接器错误multiple definition of 'x'。老实说,我期待这一点,但由于x没有在任何地方使用 odr(据我所知),我看不出标准如何限制这一点。还是未定义的行为?

0 投票
2 回答
1038 浏览

gcc - 让 GCC 链接器警告多个函数定义

考虑我的小示例 C 库:

它计划让 some_function() 可以公开调用。但是,该库不起作用,因为它所需的外部库也恰好使用了一个名为 some_function() 的函数,该函数恰好具有相同的原型。不过,GCC 的链接器并不关心 some_function 符号的来源有多少。它看似随机选择一个,外部库可能会也可能不会使用我的 some_function() 而不是它自己的。疯了吧。不是图书馆不工作的事实。这个库绝对不应该工作。更重要的是符号“some_function”有两个来源,但链接器对此没有做任何事情。而且你知道,这并没有让我太困扰,因为我习惯了 GCC 和 C 通常默认情况下是病态的鲁莽。一定有办法 但是,当同一个符号有两个来源时,让链接器警告我。我已经尝试过 -Wall -Wextra -Wshadow,但这不会产生任何警告。

请注意,-fvisibility=hidden 在这里没有帮助,因为两个库都想导出 some_function()。我知道您可以对我在没有唯一前缀的情况下进行函数调用感到羞耻。你是对的。这是一个错误。我不在乎。这个错误可以被链接器捕获,因此应该被捕获。链接器没有理由不捕捉这个错误。此外,您使用的库可能会导出一些奇怪的意外符号,并且您不一定可以控制其他人的库导出的内容。只有在程序员停下来并着火之前,那个和前缀才能变得如此独特。

0 投票
1 回答
905 浏览

c++ - 内联导致模板类的特殊成员函数覆盖虚函数被忽略

我想和你们分享一个我偶然发现的奇怪例子,这让我思考了两天。

要使此示例正常工作,您需要:

  • 三角形虚继承(关于成员函数getAsString()
  • Value<bool>::getAsString()覆盖虚函数的模板类(此处为 )的成员函数特化
  • 由编译器(自动)内联

你从一个模板类开始,它实际上继承了一个公共接口——即一组虚拟函数。稍后,我们将专门研究这些虚函数之一。内联可能会导致我们的特化被忽视。

接下来,我们必须继承这个类和一个本身也需要模板化Value的类中的接口:Parameter

现在,不要(!)给出Value类型等于 bool 的特化的前向声明......

但相反,只需像这样给出它的定义......

..但在另一个模块中(这很重要)!

最后,我们有一个main()函数来测试正在发生的事情:

如果您按如下方式编译代码(我将其放入名为 test1.cpp 和 test2.cpp 的两个模块中,后者仅包含专业化和必要的声明):

输出是

如果您使用-O0或仅编译-fno-inline- 或者如果您确实给出了专业化的前向声明 - 结果将变为:

有趣,不是吗?

到目前为止我的解释是:内联在第一个模块(test.cpp)中起作用。所需的模板函数被实例化,但有些函数最终被内联在对Parameter<bool>::getAsString(). 另一方面,valbool这不起作用,但模板被实例化并用作函数。然后链接器找到实例化的模板函数和第二个模块中给出的专用函数,并决定后者。

你怎么看呢?

  • 你认为这种行为是一个错误吗?
  • 为什么内联适用于Parameter<bool>::getAsString()但不适用于Value<bool>::getAsString()虽然两者都覆盖了虚函数?
0 投票
2 回答
1408 浏览

c++ - 我可以对静态、constexpr、类内初始化的数据成员做什么?

这可能是一个不寻常的问题,因为它要求对另一个问题的简短回答以及与之相关的 C++11 标准的某些方面进行更全面的解释。

为了便于参考,我将在这里总结参考的问题。OP 定义了一个类:

并且想知道为什么他对类内初始化静态数据成员的使用没有错误(一本书提到这是非法的)。Johannes Schaub 的回答指出:

  1. 这违反了单一定义规则
  2. 不需要诊断。

尽管我依赖这个答案的来源和有效性,但老实说我不喜欢它,因为我个人觉得它太神秘了,所以我试图自己想出一个更有意义的答案,但只取得了部分成功。相关似乎是§ 9.4.2/4:

“在程序中使用 odr (3.2)的静态数据成员应该有一个确切的定义;不需要诊断 [重点是我的]

这让我更接近一点。这就是第 3.2/2 节定义odr-used变量的方式:

“名称显示为潜在求值表达式的变量是 odr-used除非它是满足出现在常量表达式 (5.19) 中的要求并且立即应用左值到右值转换 (4.1) 的对象” [重点是我的]

在OP的问题中,变量period显然满足出现在常量表达式中的要求,是一个constexpr变量。所以肯定要在第二个条件中找到原因:并且立即应用左值到右值的转换(4.1)

这是我在解释标准时遇到困难的地方。这第二个条件实际上意味着什么?它涵盖哪些情况?这是否意味着如果静态constexpr变量是从函数返回的,则它不会被ODR 使用(因此可以在类内初始化)?

更一般地说:你可以对静态constexpr变量做什么,以便你可以在课堂上初始化它?

0 投票
3 回答
2085 浏览

c++ - 为什么在头文件中定义类时没有多重定义错误?

我不确定我是否正确地提出了这个问题,但让我解释一下。

首先,我阅读了这篇解释声明和定义之间区别的文章: http ://www.cprogramming.com/declare_vs_define.html

其次,我从之前的研究中知道,在头文件中定义变量和函数是不好的做法,因为在链接阶段,您可能有多个同名定义,这会引发错误。

但是,为什么上课不会发生这种情况?根据另一个SO答案( 定义和声明之间有什么区别?),以下将是一个类定义:

如果上面的定义在头文件中。然后,据推测,您可以拥有多个 #include 该标头的 .cpp 文件。这意味着该类在多个 .o 文件中编译后多次定义,但似乎不会造成太多问题......

另一方面,如果它是在头文件中定义的函数,它显然会导致问题......据我了解......也许?

那么类定义有什么特别之处呢?

0 投票
3 回答
2217 浏览

c++ - 内联函数和类和头文件

  1. 头文件中定义的任何函数都会自动内联吗?
  2. 如果我在一个类中声明一个函数并在外部使用关键字 inline 给出定义,这个函数会是内联的吗?如果是的话,为什么这不违反内联函数在声明时应该被赋予主体的法律?