为什么编译器不在同一翻译单元中警告 ODR 违规
Why doesn't the compiler warn against ODR violations in the same translation unit
在同一个翻译单元中,ODR问题很容易诊断。 那么,为什么编译器不警告同一翻译单元中的 ODR 违规行为呢?
例如,在下面的代码 https://wandbox.org/permlink/I0iyGdyw9ynRgny6(下面转载)中,检测是否已定义std::tuple_size
时存在 ODR 冲突。 此外,当您取消注释three
和four
的定义时,未定义的行为很明显。 程序的输出将更改。
只是试图理解为什么ODR违规行为如此难以捕捉/诊断/可怕。
#include <cstdint>
#include <cstddef>
#include <tuple>
#include <iostream>
class Something {
public:
int a;
};
namespace {
template <typename IncompleteType, typename = std::enable_if_t<true>>
struct DetermineComplete {
static constexpr const bool value = false;
};
template <typename IncompleteType>
struct DetermineComplete<
IncompleteType,
std::enable_if_t<sizeof(IncompleteType) == sizeof(IncompleteType)>> {
static constexpr const bool value = true;
};
template <std::size_t X, typename T>
class IsTupleSizeDefined {
public:
static constexpr std::size_t value =
DetermineComplete<std::tuple_size<T>>::value;
};
} // namespace <anonymous>
namespace std {
template <>
class tuple_size<Something>;
} // namespace std
constexpr auto one = IsTupleSizeDefined<1, Something>{};
// constexpr auto three = IsTupleSizeDefined<1, Something>::value;
namespace std {
template <>
class tuple_size<Something> : std::integral_constant<int, 1> {};
} // namespace std
constexpr auto two = IsTupleSizeDefined<1, Something>{};
// constexpr auto four = IsTupleSizeDefined<1, Something>::value;
int main() {
std::cout << decltype(one)::value << std::endl;
std::cout << decltype(two)::value << std::endl;
}
为了使模板编译速度更快,编译器会记住它们。
由于 ODR 保证模板的全名及其参数完全定义了它的含义,因此一旦实例化模板并生成"它是什么",您就可以存储从其名称(所有参数命名)到"它是什么"的表。
下次您向模板传递其参数时,它不会尝试再次实例化它,而是在记忆表中查找它。 如果找到,它将跳过所有这些工作。
为了执行所需的操作,编译器必须放弃此优化,并在每次传递模板参数时重新实例化模板。 这可能会导致构建时间大幅减慢。
在你的玩具代码中,也许不是,但在真正的项目中,你可以有数千个独特的模板和数十亿个模板实例化,记忆可以将模板实例化时间减少一百万倍。
相关文章:
- 警告处理为错误这里有什么问题
- 什么时候调用组成单元对象的析构函数
- 不同翻译单元中不可重载的非内联函数定义
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- cppcheck在const std::string[]上引发警告
- GCC对可能有效的代码抛出init list生存期警告
- 如何在BST的这个简单递归实现中消除警告
- 关于std::move的使用,是否有编译警告
- g++ 在某个类成员未初始化时不发出警告
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 在子目录中使用target_sources()命令时用于单元测试(qtest)的项目结构
- VC++本机单元测试,找不到调试符号
- 将QIcon添加到QTableView单元格
- 如何处理来自核心指南检查器的关于gsl::at的静态分析警告
- 用于交叉编译和CMake的预处理器宏的单元测试
- 当用户在qtablewidget中输入单元格时,如何获得信号?C++
- 使用typeid警告未使用的变量
- 示例C++项目编译中的警告
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 为什么编译器不在同一翻译单元中警告 ODR 违规