提问人:Amir Kirsh 提问时间:2/14/2023 最后编辑:Amir Kirsh 更新时间:8/24/2023 访问量:283
编译器是否可以决定忽略依赖类型上缺少的类型名,而 C++20 仍然需要它?
Can a compiler decide to ignore a missing typename on dependent type where it is still required by C++20?
问:
以下代码使用 MSVC 进行编译,但因在依赖类型之前缺少 GCC 和 Clang 而失败:typename
struct Foo { struct value{ }; };
struct Bar { int value; };
template<typename T>
constexpr size_t SIZE = sizeof(T::value); // missing typename here, for Foo
constexpr size_t s1 = SIZE<Foo>; // missing typename before dependent type above
constexpr size_t s2 = SIZE<Bar>;
MSVC 方法(不需要 typename for )似乎是合理的,因为 sizeof 适用于类型和变量。另一方面,GCC 和 Clang 似乎照本宣科,因为即使在 C++20 中,当上下文无法向编译器显示它是否将满足类型或变量时,您仍然需要这种情况。sizeof
typename
问题是这里是否允许 MSVC 是允许的,也就是说,如果编译器可以在没有 的情况下正确执行所需的操作,是否允许这样做?还是与规范相矛盾?typename
MSVC 与 Clang 和 GCC 方法之间的差异在以下代码中体现为实际差异,该代码由所有三个编译器编译,但行为不同:
template<typename T> concept A1 = sizeof(typename T::value) > 0;
template<typename T> concept A2 = sizeof(T::value) > 0;
struct Foo { struct value{ }; };
constexpr bool v1 = A1<Foo>; // true with all
constexpr bool v2 = A2<Foo>; // true with MSVC, false with GCC and Clang
在上面的代码中,GCC 和 Clang 认为 A2 中的省略是非法的,因此无法实现这个概念,这不是编译错误,而是让概念获得布尔值 false ([temp.constr.atomic])。typename
C++ spec ([temp.res.general]) 列出了假定合格 id 为类型不需要的位置。运算符不在该列表中,因此似乎应该需要模板依赖类型。另一方面,在示例中不会显示为格式错误,不需要对缺失进行诊断(不在示例中并不能说明什么,但在某种程度上仍然保留了问题)。typename
sizeof
typename
sizeof
typename
为什么可以在不添加的情况下推断出正确的操作?主要是因为它不应该真正关心这是一个类型还是一个变量。而且规范没有具体说明这是格式不正确的。如果它确实说它格式不正确,那么指向此的指针应该是答案,这可能会使 MSVC 行为成为缺陷。sizeof
typename
顺便说一句,这并不能回答这个问题,可以通过以下代码使所有三个编译器都满意:
template<typename T>
constexpr size_t SIZE = sizeof(T::value);
template<typename T> requires requires { typename T::value; }
constexpr size_t SIZE<T> = sizeof(typename T::value);
template<typename T> concept A =
sizeof(T::value) > 0 ||
sizeof(typename T::value) > 0;
答:
关于这一点,标准是非常间接的,但很明显,MSVC 在这里不符合。(在非 SFINAE/概念的情况下,只允许发出警告(“尽管缺少'typename',但 sizeof 的操作数被认为是一个类型”)并继续,但这不是重点。
请注意,即使在微不足道的情况下
struct X;
int y=X;
错误在于不能解释为 unqualified-id,因为它没有“适当声明”([expr.prim.id.unqual]/1)。在模板中,从属名称的语法解释是由 的存在与否决定的,尽管 qualified-ids 因此是在不知道它们的终端名称是否如此合适的情况下产生的;如果最终发现它们在这方面有所欠缺,我们显然必须拒绝它们。X
typename
评论
typename
/permissive-
typename
typename
typename