c++ - 了解模板类型/值的重复评估
问题描述
我有以下代码,我不明白为什么只有在我没有在定义之前!has_size<Bar>::value
注释掉完全相同的情况下最后一个评估为真static_assert( !has_size<Bar>::value, ...)
Bar
#include <type_traits>
template <class, class = void> struct has_size : std::false_type {};
template <class T> struct has_size<
T, typename std::enable_if<(sizeof(T) > 0)>::type>
: std::true_type
{};
// expected success
struct Foo {};
static_assert( has_size<Foo>::value, "Foo doesn't have size");
struct Bar; // declare bar
// if we comment out this line, the static_assert below struct Bar{} fails
static_assert( !has_size<Bar>::value, "Bar has a size");
struct Bar {}; // define bar
// why is this true now, but false if I comment out the previous assertion?
static_assert( !has_size<Bar>::value, "Bar has a size");
我想稍后根据has_size<Bar>
. msvc、gcc 和 clang 的行为相同。我试图弄清楚这是否是有意的和有据可查的行为,或者我是否正在通过这种行为徘徊在 UB 土地或其他一些灾难中。想法?
解决方案
您可以将类模板实例化视为“缓存”或“记忆”。更正式地说,类模板的每个翻译单元都有一个实例化点。
所以当你写:
struct Bar;
static_assert( !has_size<Bar>::value, "Bar has a size"); // #1
struct Bar {};
static_assert( !has_size<Bar>::value, "Bar has a size"); // #2
has_size<Bar>
在 被实例化#1
。这是它唯一的实例化点。在#2
,我们不会“重做”那个计算——所以它仍然是错误的。如果我们从不同的翻译单元再次执行此操作,以给出不同答案的方式,那将是格式错误的(不需要诊断),但在这种情况下 - 这是一个格式正确的程序。
当您注释掉时#1
,现在的实例化点has_size<Bar>
变为#2
. 并且在程序的那个点上,Bar
完成了,has_size<Bar>
现在也是true_type
......所以静态断言触发了。
推荐阅读
- typescript - 更改使用“tsc --init”创建的 tsconfig.json 的默认设置?
- django - 当我将它包含在父模板中时,Django 模型表单不显示
- node.js - 为什么在 NodeJS 上发出很多请求很慢?
- java - 使用 Spring Cloud Open Feign 获取 JSON 中的对象列表
- excel - 从单词表单元格复制数据会引发类型不匹配错误
- apache-spark - 使用 pyspark 删除连字符和空格
- razorpay - 如何从我的 razorpay 账户余额转帐到用户 UPI ID 或银行账户
- linux - 为什么设置 ipvsadm 后在 netstat 列表中找不到监听端口?
- angular - 如何在 Angular 12.x 中导入传单控制地理编码器?
- python - 调整图黄砖模型-python