`std::tuple_size_v`在不同编译器上的不同SFINAE行为

发布时间:2022-06-23 / 作者:清心寡欲
本文介绍了`std::tuple_size_v`在不同编译器上的不同SFINAE行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下代码:

#include 
#include 
#include 

template  struct is_tuple_like : std::false_type {};
template  struct is_tuple_like, void())> : std::true_type {};

int main()
{
    std::cout << is_tuple_like::value << '
';
}

Run on gcc.godbolt.org

在GCC 10.2和MSVC19.28上,它会导致硬错误,大致如下:

error: incomplete type 'std::tuple_size<...>' used in nested name specifier

另一方面,在Clang 11.0.1上,它使用libstdc++和libc++编译和打印1

此处哪个编译器正确?

请注意,Clang打印1而不是0,这意味着它不会将std::tuple_size::value(tuple_size_v的初始值设定项)视为软错误,而是选择完全忽略它!

这在某种程度上是有道理的,因为如果tuple_size_v定义为template inline constexpr size_t tuple_size_v = ...,则decltype(tuple_size_v<...>)类型不依赖于模板参数,始终为size_t

我想问题可以归结为是否需要在此处实例化tuple_size_v的初始值设定项,即使它不是严格必需的。


我知道我可以通过将std::tuple_size_v<...>替换为std::tuple_size<...>::value来修复它,然后它会在所有三个编译器上打印0

推荐答案

我认为Lang有这个权利。

[temp.inst]/7中的规则为:

除非变量模板专门化是声明的专门化,否则在需要存在变量定义的上下文中引用变量模板专门化时,或者如果该定义的存在影响程序的语义,则会隐式实例化该变量模板专门化。

此程序不需要std::tuple_size_v定义,只需要声明。和声明:

template 
inline constexpr size_t tuple_size_v = tuple_size::value;

足以计算部分专门化中的表达式。decltype(std::tuple_size_v, void())根本不依赖于此处的值,对于任何size_t,这都是void类型的有效表达式。

我们处理的是函数模板而不是变量模板:

template 
constexpr size_t tuple_size_v() { return tuple_size::value; }

可能更清楚的是,我们不需要定义,只需要声明,GCC和MSVC都接受这种替代提法(事实上,GCC甚至警告它没有意义):example。

稍后,在[temp.inst]/8中,我们有:

如果某个表达式([expr.const])的常量求值需要该变量或函数,即使不需要该表达式的常量求值,或者常量表达式求值不使用该定义,则认为该变量或函数的定义的存在会影响程序的语义。

但情况并非如此:我们不需要变量来进行常量计算。

这篇关于`std::tuple_size_v`在不同编译器上的不同SFINAE行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持吉威生活!



[英文标题]Different SFINAE behavior of `std::tuple_size_v` on different compilers


声明:本媒体部分图片、文章来源于网络,版权归原作者所有,如有侵权,请联系QQ:330946442删除。