C++类型漏洞解释

6

一个简单的问题:能否有人解释一下这段代码是如何工作的?(来自这里https://alexpolt.github.io/type-loophole.html

#include <string>
#include <type_traits>

template<int N> struct tag{};

template<typename T, int N>
struct loophole_t {
  friend auto loophole(tag<N>) { return T{}; };
};

auto loophole(tag<0>);

int main() {

sizeof( loophole_t<std::string, 0> );
    
static_assert(std::is_same< std::string, decltype( loophole(tag<0>{}) ) >::value);

}

看起来 sizeof( loophole_t<std::string, 0> ); 影响编译器的全局状态。我的意思是,如果我们删除这行代码,static_asserts 将会失败。C++允许这种情况吗?

更新: 刚刚意识到它取决于编译器甚至编译器版本。 在任何GCC >=8(可能也适用于早期版本)中都可以很好地工作。 在clang >= 10中无法编译,但在clang 7.0中可以正常工作。

所以我的真正问题是:这是编译器 bug 还是标准行为?


@Dmitry 运行正常。 - Asteroids With Wings
@Dmitry 因为您试图使用相同的标签“保存”两种类型。我相信这是有意设计的。 - Asteroids With Wings
这实际上很有趣,与在类定义内首次声明朋友时的作用域有关。我不知道Clang是否正确。 - Asteroids With Wings
进一步证明了clang中friend的普遍bug问题 - Asteroids With Wings
哦,是的,这就是它 https://godbolt.org/z/Os2oGo - Dmitry
显示剩余7条评论
1个回答

4

它引起模板特化loophole_t<std::string, 0>的实例化。

作为一个带有friend函数的类模板(请记住,friend不是成员),这也在全局命名空间中引入了该函数

该函数可以被拼写为std::string loophole(tag<0> unusedParam);

它除了在之后进行一次可抛弃的sizeof之外,并没有直接用于任何其他目的,只是通过decltype检索其返回类型并将其与std::string进行静态断言比较(这预计会通过演示方式)。

作者已经在表达式tag<0>中“存储”了std::string。有点。

如果您编写了更多内容:

sizeof( loophole_t<std::string, 0> );
sizeof( loophole_t<int, 1> );
sizeof( loophole_t<char, 2> );

如果不小心在代码中定义了太多函数,就会导致很多函数处于作用域内,这些函数可能会被拼写错误:

std::string loophole(tag<0> unusedParam);
int loophole(tag<1> unusedParam);
char loophole(tag<2> unusedParam);

现在你可以看到函数声明为每个标签“存储”了一个类型。我们可以使用标签“访问”这些类型:

decltype(loophole(tag<0>{})) thisIsAString = "lol";
decltype(loophole(tag<1>{})) thisIsAnInt = 42;
decltype(loophole(tag<2>{})) thisIsAChar = '!';

我不知道这有什么实际好处。但如果你非常需要它,你可以:

using MyTypes = std::tuple<std::string, int, char>;

然后使用更加通俗易懂的方式来提取类型为N的值


回复:“实际好处”:反射。例如,获取结构体成员的类型。否则,你会怎么做呢? - pmor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接