Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么';t编译器警告同一翻译单元中的ODR冲突_C++_Templates_C++17_One Definition Rule - Fatal编程技术网

C++ 为什么';t编译器警告同一翻译单元中的ODR冲突

C++ 为什么';t编译器警告同一翻译单元中的ODR冲突,c++,templates,c++17,one-definition-rule,C++,Templates,C++17,One Definition Rule,在同一个翻译单元中,ODR问题很容易诊断。那么,为什么编译器不警告同一翻译单元中的ODR冲突呢 例如,在以下代码(如下所示)中,检测是否定义了std::tuple_size,存在ODR冲突。而且,当您取消注释three和three的定义时,未定义的行为也很明显。程序的输出发生变化 只是想了解为什么ODR违规行为很难发现/诊断/吓人 #包括 #包括 #包括 #包括 分类{ 公众: INTA; }; 名称空间{ 模板 结构确定完成{ 静态constexpr const bool值=false; }

在同一个翻译单元中,ODR问题很容易诊断。那么,为什么编译器不警告同一翻译单元中的ODR冲突呢

例如,在以下代码(如下所示)中,检测是否定义了
std::tuple_size
,存在ODR冲突。而且,当您取消注释
three
three
的定义时,未定义的行为也很明显。程序的输出发生变化

只是想了解为什么ODR违规行为很难发现/诊断/吓人


#包括
#包括
#包括
#包括
分类{
公众:
INTA;
};
名称空间{
模板
结构确定完成{
静态constexpr const bool值=false;
};
模板
结构确定完成<
不完全类型,
std::如果>{
静态constexpr const bool值=真;
};
模板
类是整数定义的{
公众:
静态constexpr std::size\u t值=
确定完成::值;
};
}//名称空间
名称空间标准{
模板
类元组大小;
}//名称空间std
constexpr auto one=IsTupleSizeDefined{};
//constexpr auto three=IsTupleSizeDefined::value;
名称空间标准{
模板
类元组大小:std::integral_常量{};
}//名称空间std
constexpr auto two=IsTupleSizeDefined{};
//constexpr auto-four=IsTupleSizeDefined::value;
int main(){

std::cout为了使模板编译速度更快,编译器将它们存储起来

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

下次你将模板传递给它的参数时,它不再尝试再次实例化它,而是在备忘录表中查找它。如果找到,它将跳过所有这些工作

为了做你想做的事情,编译器必须放弃这种优化,每次你传递模板参数时都要重新实例化模板。这可能会导致构建时间的大幅放缓


在你的玩具代码中,也许不是这样,但在一个真实的项目中,你可以拥有数千个独特的模板和数十亿个模板实例化,备忘录可以将模板实例化时间减少一百万倍。

它不必按照标准诊断这些错误(即使在能够检测到它们的情况下拥有一些模板也可以)@Jarod42是的,但是为什么?速度是唯一的因素吗?@奇怪的是,我可以写一些代码,由于模板实例化递归限制,在没有记忆的情况下无法编译,但是在没有记忆的情况下可以编译。并且在没有记忆的情况下以O(n^2)和O(n)进行编译。我不保证没有其他原因,包括“一般来说,解决这个问题很难,即使你的具体案例很简单,为什么要费心在简单的案例中解决这个问题,因为解决这个问题很昂贵。”。我只是提供了一个充分的理由,真的。
#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;
}