[英]Accessing member type with `if constexpr` inside generic lambda requires both branches to be well-formed - gcc vs clang
Consider two struct
s with different member type aliases: 考虑具有不同成员类型别名的两个struct
:
struct foo { using x = int; };
struct bar { using y = float; };
Given a T
in a template
context, I want to get either T::x
or T::y
depending on what T
is: 给定template
上下文中的T
,我想得到T::x
或T::y
具体取决于T
是什么:
template <typename T>
auto s()
{
auto l = [](auto p)
{
if constexpr(p) { return typename T::x{}; }
else { return typename T::y{}; }
};
return l(std::is_same<T, foo>{});
}
int main()
{
s<foo>();
}
g++
compiles the code above, while clang++
produces this error: g++
编译上面的代码,而clang++
产生这个错误:
error: no type named 'y' in 'foo'
else { return typename T::y{}; }
~~~~~~~~~~~~^
note: in instantiation of function template specialization 's<foo>' requested here
s<foo>();
^
on godbolt.org , with conformance viewer 在godbolt.org上 ,有一致性查看器
Is clang++
incorrectly rejecting this code? clang++
是否错误地拒绝了此代码?
Note that clang++
accepts the code when removing the indirection through the generic lambda l
: 请注意, clang++
在通过通用lambda l
删除间接时接受代码:
template <typename T>
auto s()
{
if constexpr(std::is_same<T, foo>{}) { return typename T::x{}; }
else { return typename T::y{}; }
}
See Richard Smith's post on std-discussion: 请参阅Richard Smith关于std讨论的帖子 :
In the implementation I'm familiar with [ie Clang], a key problem is that the lexical scopes used while processing a function definition are fundamentally transient, which means that delaying instantiation of some portion of a function template definition is hard to support. 在我熟悉[即Clang]的实现中,一个关键问题是在处理函数定义时使用的词法范围基本上是暂时的,这意味着延迟函数模板定义的某些部分的实例化很难支持。 Generic lambdas don't suffer from a problem here, because the body of the generic lambda is instantiated with the enclosing function template, [..] 通用lambda不会遇到问题,因为泛型lambda的主体用封闭的函数模板实例化,[...]
That is, generic lambdas' bodies are partially instantiated using the local context (including template arguments) when the template is instantiated; 也就是说,在实例化模板时,使用本地上下文(包括模板参数)部分地实例化通用lambdas的主体; thus under Clang's implementation, T::x
and T::y
are substituted directly, since the closure type could be passed outside. 因此,在Clang的实现中, T::x
和T::y
被直接替换,因为闭包类型可以传递到外部。 This leads to the failure. 这导致了失败。 As pointed out by @TC, the code can be considered ill-formed, no diagnostic required, as the instantiation of s<foo>
yields a template definition (that of the closure) whose second if constexpr
branch has no well-formed instantiations. 正如@TC所指出的,代码可以被认为是不正确的,不需要诊断,因为s<foo>
的实例化产生模板定义(闭包的模板定义),其第二个if constexpr
分支没有良好形成的实例化。 This explains the behaviour of both Clang and GCC. 这解释了Clang和GCC的行为。
This boils down to an architectural issue in a major implementation (see also this answer ; GCC apparently doesn't suffer from this limitation), so I'd be surprised if Core would deem your code well-formed (after all, they accounted for this in the design of generic lambda captures--see the linked answer). 这归结为一个主要实现中的架构问题(另见这个答案 ; GCC显然没有受到这个限制),所以如果Core认为你的代码格式正确(毕竟,他们占了这在通用lambda捕获的设计中 - 参见链接的答案)。 GCC supporting your code is, at best, a feature (but probably harmful, since it enables you to write implementation-dependent code). 支持代码的GCC充其量只是一个功能(但可能有害,因为它使您能够编写依赖于实现的代码)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.