简体   繁体   English

在通用lambda中使用`if constexpr`访问成员类型需要两个分支都是格式良好的 - gcc vs clang

[英]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::xT::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::xT::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.

相关问题 如果 constexpr 格式正确,这是在内部使用 static_assert 吗? - Is this use of static_assert inside if constexpr well-formed? 在另一个成员函数的尾随返回类型中获得推断成员函数的decltype是否格式良好? - Is getting the decltype of a deduced member function inside the trailing return type of another member function well-formed? 从泛型lambda调用`this`成员函数 - clang vs gcc - Calling `this` member function from generic lambda - clang vs gcc Clang声称constexpr成员的通用lambda参数不是constexpr - Clang claims constexpr member of generic lambda argument is not constexpr 通过引用调用`constexpr`成员函数-clang vs gcc - Invoking `constexpr` member function through reference - clang vs gcc 静态constexpr变量的自我初始化是否格式良好? - Self-initialization of a static constexpr variable, is it well-formed? 在非`constexpr`上下文中的`constexpr`函数中使用lambda:clang vs gcc - Using a lambda in a `constexpr` function in a non-`constexpr` context: clang vs gcc `decltype` 的广义 lambda 在 lambda 体内捕获 - gcc 与 Z2C5517DB7BC397CEF9A7754FFZA1 - `decltype` of generalized lambda capture inside body of a lambda - gcc vs clang clang vs gcc-空的通用lambda可变参数包 - clang vs gcc - empty generic lambda variadic argument pack 为什么{1,2}没有类型,但是decltype(a)格式正确? - Why does {1, 2} has no a type, but decltype(a) is well-formed?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM