Why doesn't the compiler warn against ODR violations in the same translation unit

我们两清 提交于 2020-07-05 11:38:05

问题


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?

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.

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

回答1:


To make template compiling fast, compilers memoize them.

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.



来源:https://stackoverflow.com/questions/45922191/why-doesnt-the-compiler-warn-against-odr-violations-in-the-same-translation-uni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!