C++类型漏洞解释

C++ type loophole explanation

愚蠢的问题。谁能向我解释这段代码是如何工作的? (来自这里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++ 允许吗?

更新: 刚刚意识到它取决于编译器甚至编译器版本。 适用于任何 >=8 的 GCC(可能也适用于旧版本)。 不能用 clang >= 10 编译,但可以用 clang 7.0

正常工作

所以我要说我真正的问题是编译器错误还是标准行为?

它导致模板特化的实例化loophole_t<std::string, 0>

作为具有 friend 函数的 class 模板(请记住,friend 不是成员),全局命名空间中的 also brings the function into scope

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

除了用 sizeof 之后,它不会直接用于任何其他用途,除了用 decltype“检索”它的 return 类型并将其与 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>;

…然后使用somewhat more idiomatic means to extract type N.