为何编译器不针对同一翻译单元中的ODR违规发出警告 [英] Why doesn't the compiler warn against ODR violations in the same translation unit

查看:123
本文介绍了为何编译器不针对同一翻译单元中的ODR违规发出警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在同一翻译单元中,易于诊断ODR问题.为什么然后编译器不对同一翻译单元中的ODR违规发出警告?

In the same translation unit, ODR problems are easy to diagnose. Why then does the compiler not warn against ODR violations in the same translation unit?

例如在以下代码中 https://wandbox.org/permlink/I0iyGdyw9ynRgny6 (已复制下面的内容),则会检测到是否已定义std::tuple_size,从而违反了ODR.而且,当您取消注释threefour的定义时,未定义的行为也很明显.程序的输出更改.

For example in the following code https://wandbox.org/permlink/I0iyGdyw9ynRgny6 (reproduced below), there is an ODR violation with detecting if std::tuple_size has been defined. And further the undefined behavior is evident when you uncomment the defintiions of three and four. The output of the program changes.

只是想了解为什么为什么很难发现/诊断/吓跑违反ODR的行为.

Just trying to understand why ODR violations are so hard to catch/diagnose/scary.

#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;
}

推荐答案

为使模板快速编译,编译器会对其进行记忆.

To make template compiling fast, compilers memoize them.

因为ODR保证模板的全名及其参数完全定义了含义,所以一旦实例化模板并生成它是什么",就可以将表从其名称(所有参数都命名为)存储到是什么".

Because ODR guarantees that the full name of a template and its arguments fully defines what it means, once you instantiate a template and generate "what it is", you can store a table from its name (with all arguments named) to "what it is".

下次您传递模板的参数时,它不会尝试再次实例化它,而是在备注表中查找它.如果找到,它将跳过所有工作.

The next time you pass the template its arguments, instead of trying to instantiate it again, it looks it up in the memoization table. If found, it skips all of that work.

为了做您想做的事情,编译器必须在每次传递参数时放弃该优化并重新实例化模板.这可能会大大缩短构建时间.

In order to do what you want, the compiler would have to discard this optimization and re-instantiate the template every time you passed it arguments. This can cause a massive slowdown of build times.

在玩具代码中,也许不是,但是在一个实际项目中,您可能有数千个唯一的模板和数十亿个模板实例化,因此备忘录可将模板实例化时间减少一百万倍.

In your toy code, maybe not, but in a real project you could have thousands of unique templates and billions of template instantiations, the memoization can reduce template instantiation time by a factor of a million.

这篇关于为何编译器不针对同一翻译单元中的ODR违规发出警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆