gpt4 book ai didi

Illegal use of undefined type(非法使用未定义的类型)

转载 作者:bug小助手 更新时间:2023-10-26 20:09:05 25 4
gpt4 key购买 nike



Considering the code example shown below, is decltype(h{}.t()); a legal expression? Which specific rule in the C++20 standard either allows or forbids this?

考虑到下面显示的代码示例,decltype(h{}.t());是合法的表达式吗?C++20标准中的哪个特定规则允许或禁止这样做?


struct d;
struct h { static auto t() -> d; };

using a = decltype(h::t()); // all ok
using b = decltype(decltype(h{})::t()); // all ok
using c = decltype(h{}.t()); // clang ok, gcc ok, msvc nope

Live example

现场示例




The error message produced by MSVC:

MSVC产生的错误消息:


<source>(6): error C2027: use of undefined type 'd'
<source>(1): note: see declaration of 'd'



Having stumbled upon yet another bug with MSVC, I've actually discovered a workaround for MSVC's deviating behavior. By simply providing a user-defined defaulted default constructor for type h, MSVC no longer complains about d being undefined.

在偶然发现了MSVC的另一个错误之后,我实际上已经发现了一种解决MSVC偏离行为的方法。只需为类型h提供一个用户定义的默认构造函数,MSVC就不再抱怨d未定义。


struct d;
struct h {
static auto t() -> d;
h() = default;
};
using c = decltype(h{}.t()); // all ok

However, the problem still seems to persist when skipping use of h's constructor, like with the use of std::declval for example (as in: decltype(std::declval<h>().t());). Also, be aware that by providing a user-defined default constructor, even when defaulted, this will cause h to no longer be considered an aggregate type.

但是,当跳过h的构造函数的使用时,问题似乎仍然存在,例如使用std::declval(如:decltype(std::declval ().t());)。另外,请注意,通过提供用户定义的默认构造函数,即使在默认情况下,这也会导致h不再被视为聚合类型。


更多回答

Does std::declval<h>().t() behave any different in MSVC?

Std::decval().t()在MSVC中的行为有什么不同吗?

@StoryTeller-UnslanderMonica, fails with the same error, it wants you to define d.

@storytaler-UnslanderMonica失败,并返回相同的错误,它希望您定义d。

@Blindy This might be very useful in generic code. As a simple example consider a function that returns/uses a container size. A member function size() could be a static one for a compile-time-sized container and a non-static one if container size is determined at run-time.

@bllindy这在泛型代码中可能非常有用。作为一个简单的例子,考虑一个返回/使用容器大小的函数。对于编译时大小的容器,成员函数SIZE()可以是静态的,如果容器大小是在运行时确定的,则可以是非静态的。

优秀答案推荐

It is explicitly permitted for the type of a prvalue expression operand to decltype to be incomplete. Temporary materialization is exceptionally not applied in this circumstance, so that a destructor of d isn't necessary either (which would require d to be complete to lookup the destructor). So d doesn't need to be complete. For reference to the standard see [dcl.type.decltype]/2.

显式允许PrValue表达式操作数的类型dectype不完整。在这种情况下,临时物化例外地不适用,因此也不需要d的析构函数(这将要求d完成对析构函数的查找)。所以d不需要是完整的。关于该标准的参考见[dcl.type.decltype]/2。


The function t may also be undefined, because use in a decltype operand is not use in a potentially-evaluated expression and therefore not an odr-use.

函数t也可以是未定义的,因为在decltype操作数中使用不会在可能求值的表达式中使用,因此不会使用ODR。


Constructing a h object with h{} also doesn't demand either t to be defined or d to be complete.

使用h{}构造h对象也不需要定义t或完成d。


The standard even includes a very similar example (see link above).

该标准甚至包括一个非常相似的例子(参见上面的链接)。


So MSVC is wrong here.

因此,MSVC在这一点上是错误的。


更多回答

It seems that in order to call t by using the member access operator ., h will have to be materialized, and this shouldn't be a problem since h is complete. If, for example, h's destructor is marked as deleted, and when trying decltype([]<typename T = h>() -> T {}().t());, all compilers reject this as h has to be materialized which invokes its deleted destructor implicitly.

似乎为了通过使用成员访问操作符.来调用t,h必须被具体化,这应该不是问题,因为h是完整的。例如,如果h的析构函数被标记为已删除,并且在尝试dectype([]()->T{}().T());时,所有编译器都会拒绝此操作,因为h必须被物化,这将隐式调用其已删除的析构函数。

So, since h can be materialized in the provided example, the use of t shouldn't be different from any other type of declared but undefined function, which I think is best described in [dcl.type.decltype]/note-2: "... a class type is not instantiated as a result of being the type of a function call ... so the usual reasons for requiring a complete type do not apply".

因此,由于h可以在所提供的示例中实现,所以t的使用不应该与任何其他类型的已声明但未定义的函数不同,我认为在[dcl.type.decltype]/note-2中对此进行了最好的描述:“……类类型不会作为函数调用的类型而被实例化……所以要求完整类型的通常原因并不适用”。

"all compilers reject this as h has to be materialized which invokes its deleted destructor implicitly": A temporary object of type h has to be materialized. A materialized temporary object is always destroyed at the end of the full-expression, which here is the whole decltype operand, so the destructor of h is used and therefore must not be deleted, yes.

“所有编译器都拒绝这样做,因为h必须被物化,这将隐式调用其已删除的析构函数”:必须物化h类型的临时对象。物化的临时对象总是在完整表达式的末尾销毁,这里是整个dectype操作数,所以使用h的析构函数,因此不能删除,是的。

@303 Yes, the part above the note is the normative equivalent that says that no materialization, and therefore no destructor invocation, happens for the d prvalue (which is the contentious part).

@303是的,注释上面的部分是规范上的等价物,说明对于dPrValue(这是有争议的部分),没有物化发生,因此也没有析构函数调用。

After doing some tests with mutable subojects of a constexpr variable, which led me to the discovery of (yet) another bug that seems to point to the root cause of MSVC's deviating behavior, I actually stumbled upon a rather surprising workaround for MSVC (refer to my original post).

在使用conexpr变量的可变子对象进行了一些测试后,我发现了另一个错误,它似乎指向了MSVC偏离行为的根本原因,实际上我偶然发现了一个相当令人惊讶的MSVC解决方法(请参阅我最初的帖子)。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com