问题标签 [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.
c++ - 如何在不指定类名的情况下专门化模板?
我想做一个函数debug
,输出一些关于对象的信息。我的系统包含许多不同类型的对象;其中一些包含其他对象。
我希望函数输出name
参数的成员(如果有的话),或者调试contents
参数的成员(如果有的话)。我想出了以下代码:
在这里, 和 的代码pack
几乎line
相同!我想避免多次编写相同的代码:
但是这种语法与“简单”对象的函数模板冲突(具有相同的签名)。
我怎样才能重写我的代码?我不想重写第一部分(对 , 等的声明dog
)human
,因为我的程序的那部分已经非常复杂,并且只是为了调试而向其中添加东西(基类、成员函数等)似乎不合适。
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 规则)。因此我的问题:
- 为什么输出 [EG1]、[EG3]、[EG4] 可能?
- 为什么我从不同的编译器甚至从同一个编译器得到不同的结果?这让我认为标准在这种情况下没有指定行为。
感谢您的任何建议、意见和标准解释。
更新
我想了解编译器的行为。更准确地说,如果违反了 ODR,为什么不会产生错误。一个假设是,由于UsedClass1和UsedClass2类中的所有函数都被标记为内联(因此不违反 C++03 3.2),因此链接器不会报告错误,但在这种情况下会输出 [EG1]、[EG3]、[ EG4] 看起来很奇怪。
c++ - 内联构造函数和一个定义规则
考虑以下源文件 1.cpp
2.cpp
从这些文件编译的程序是否格式正确?它的输出应该是什么?
由于违反单一定义规则或输出“1 2”,我预计链接器会出错。但是,当使用 g++ 3.4 和 VC 8.0 编译时,它会打印出“1 1”。
这怎么解释?
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)中?
在第 174 页,他有:
上层命名空间是否进入implementer.h,下层命名空间进入user.h
在他的“ dependency graph
”中,他是否重申了显而易见的事实:当 Make 运行时,对“Parser”( parser.cpp/implementer.h
) 的任何更改都会导致 driver/main.cpp 被重建——这是不必要的吗?
c++ - 如果我不使用变量,我可以在翻译单元中有多个定义吗?
该标准似乎暗示,如果不使用 odr(第 3.2/3 节),则对变量的定义数量没有限制:
每个程序都应包含该程序中 odr 使用的每个非内联函数或变量的准确定义;无需诊断。
它确实说任何变量都不能在翻译单元中多次定义(第 3.2/1 节):
任何翻译单元都不得包含一个以上的任何变量、函数、类类型、枚举类型或模板的定义。
但是我在整个程序中找不到对非 ODR 使用的变量的限制。那么为什么我不能编译如下内容:
使用 g++ 4.6.3 编译和链接这些文件,我得到一个链接器错误multiple definition of 'x'
。老实说,我期待这一点,但由于x
没有在任何地方使用 odr(据我所知),我看不出标准如何限制这一点。还是未定义的行为?
gcc - 让 GCC 链接器警告多个函数定义
考虑我的小示例 C 库:
它计划让 some_function() 可以公开调用。但是,该库不起作用,因为它所需的外部库也恰好使用了一个名为 some_function() 的函数,该函数恰好具有相同的原型。不过,GCC 的链接器并不关心 some_function 符号的来源有多少。它看似随机选择一个,外部库可能会也可能不会使用我的 some_function() 而不是它自己的。疯了吧。不是图书馆不工作的事实。这个库绝对不应该工作。更重要的是符号“some_function”有两个来源,但链接器对此没有做任何事情。而且你知道,这并没有让我太困扰,因为我习惯了 GCC 和 C 通常默认情况下是病态的鲁莽。一定有办法 但是,当同一个符号有两个来源时,让链接器警告我。我已经尝试过 -Wall -Wextra -Wshadow,但这不会产生任何警告。
请注意,-fvisibility=hidden 在这里没有帮助,因为两个库都想导出 some_function()。我知道您可以对我在没有唯一前缀的情况下进行函数调用感到羞耻。你是对的。这是一个错误。我不在乎。这个错误可以被链接器捕获,因此应该被捕获。链接器没有理由不捕捉这个错误。此外,您使用的库可能会导出一些奇怪的意外符号,并且您不一定可以控制其他人的库导出的内容。只有在程序员停下来并着火之前,那个和前缀才能变得如此独特。
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()
虽然两者都覆盖了虚函数?
c++ - 我可以对静态、constexpr、类内初始化的数据成员做什么?
这可能是一个不寻常的问题,因为它要求对另一个问题的简短回答以及与之相关的 C++11 标准的某些方面进行更全面的解释。
为了便于参考,我将在这里总结参考的问题。OP 定义了一个类:
并且想知道为什么他对类内初始化静态数据成员的使用没有错误(一本书提到这是非法的)。Johannes Schaub 的回答指出:
- 这违反了单一定义规则;
- 不需要诊断。
尽管我依赖这个答案的来源和有效性,但老实说我不喜欢它,因为我个人觉得它太神秘了,所以我试图自己想出一个更有意义的答案,但只取得了部分成功。相关似乎是§ 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
变量做什么,以便你可以在课堂上初始化它?
c++ - 为什么在头文件中定义类时没有多重定义错误?
我不确定我是否正确地提出了这个问题,但让我解释一下。
首先,我阅读了这篇解释声明和定义之间区别的文章: http ://www.cprogramming.com/declare_vs_define.html
其次,我从之前的研究中知道,在头文件中定义变量和函数是不好的做法,因为在链接阶段,您可能有多个同名定义,这会引发错误。
但是,为什么上课不会发生这种情况?根据另一个SO答案( 定义和声明之间有什么区别?),以下将是一个类定义:
如果上面的定义在头文件中。然后,据推测,您可以拥有多个 #include 该标头的 .cpp 文件。这意味着该类在多个 .o 文件中编译后多次定义,但似乎不会造成太多问题......
另一方面,如果它是在头文件中定义的函数,它显然会导致问题......据我了解......也许?
那么类定义有什么特别之处呢?
c++ - 内联函数和类和头文件
- 头文件中定义的任何函数都会自动内联吗?
- 如果我在一个类中声明一个函数并在外部使用关键字 inline 给出定义,这个函数会是内联的吗?如果是的话,为什么这不违反内联函数在声明时应该被赋予主体的法律?