对于给定的类,C ++ 14与C ++ 17更新不允许使用auto

问题描述 投票:0回答:1

什么功能使我可以将auto用于C ++ 17中的不可复制(和不可移动)类型,而不能用于C ++ 14?

请考虑以下代码:

struct A{
    A(A const&)=delete;
    A(A&&)=delete;
};

int main(){
    auto   a1 = A{}; // ok in C++17, not ok in C++14
    auto&& a2 = A{}; // ok in C++17, ok in C++14
}

事实证明,这在C ++ 14中是无效的代码,但在C ++ 17中是有效的。该行为在clang和gcc中是一致的:https://godbolt.org/z/af8mEc

我问的原因是因为直到最近我才使我的类(代表引用)不可复制,其中除其他方面还禁止使用auto,但不幸的是,事实证明现在该技术在C语言中不起作用++ 17。

换句话说,我认为C ++ 14中的行为在概念上是正确的。)]

为什么auto a1 = A{};对于C ++ 17中的不可复制类有效?是某种新的RVO机箱吗?

我认为auto在语义上由于多种可辩驳的原因而被破坏,但是至少在C ++ 14中,我可以阻止使用auto(但允许使用auto&&)。

是否有另一种方法可以防止对C ++ 17中的特定类使用auto a = A{};,还是不再使用?

Note:不久前我问了这个问题Is there a way to disable auto declaration for non regular types?,发现当时的解决方案是禁用C ++ 14中的copy and move构造函数,这在概念和语法上都有意义,但这不是C ++ 17中不再有这种情况。

c++14 c++17 copy-constructor auto move-constructor
1个回答
0
投票

在C ++ 17中,如果为用户提供某种类型的prvalue,则用户可以always使用它来初始化该类型的变量。]​​>

本质上是the definition of a prvalue has changed。在C ++ 14中,它是一个对象。具体来说,是一个临时对象。因此,类似A a = prvalue_of_type_A;的语句意味着将临时对象移至a。可以忽略该移动,但是从逻辑上讲这是一个移动,因此A必须支持移动构造。

在C ++ 17中,prvalue仅仅是对象的initializer

。初始化哪个对象取决于如何使用它。使用prvalue初始化prvalue类型的变量意味着您初始化了该对象。没有副本或移动。您可以从prvalue是一个无名对象的角度来看它,A a = prvalue_of_A;只是给该对象起一个名字,而不创建一个新对象。

而且不,您无法解决它。只要您要处理某种类型的真正prvalue,auto a = prvalue;总是会推断出prvalue的类型并直接初始化对象a,而无需复制/移动。


换句话说,我认为C ++ 14中的行为在概念上是正确的。

嗯,让我们调查一下。

此调查开始并结束时完全意识到您没有阻止auto a = A{};正常工作。您阻止了复制/移动构造,该构造具有防止该语法的side-effect

。这就是为什么保证省略会使您的“修正”变得毫无意义的原因。

通过拒绝一种类型的复制/移动构造功能,您确实确实避免了这种语法。但是在此过程中发生了很多附带损害。

您链接到的帖子给出了由于类型为non-Regular而希望禁用此语法的基本原理,出于某种原因,这使auto成为“ tricky”。忽略那些未说明的原因是否有效,您的解决方案不仅删除了“棘手的”语法。它阻止您对对象执行基本操作。

考虑将其应用于string_view的后果。您已经有了这种视图类型,并且想要通过一个多步骤过程对其进行修改。但是您想保持原始视图不变。所以自然地,您复制...哦,等等,string_view是非常规的,因此您为了防止string_view sv = prvalue;而将其复制为非法。哎呀。因此,现在我必须回到string_view的原始来源来获取另一个。假设我可以访问源,则不只是将其作为const&参数传递。

基本上,您是说拍打苍蝇的最佳方法是使用大锤。不管苍蝇有多烦人,墙[[其后

可能都更重要。所以,保证省略在概念上正确吗?好吧,保证省略的主要理由之一是允许返回prvalue的函数甚至对于不动的类型也可以工作。这实际上很重要。在C ++ 17之前,如果您想为类提供工厂功能,但从逻辑上讲类本身应该是固定不变的,那么您就不走运了。您可以选择其中一个,但不能两个都选。

让我们以您的subrange为例。在C ++ 14中,如果我想编写一个仅为某些构造函数的参数提供默认值的函数,或者使用特定的容器等,那是不可能的。我什至无法编写一个容器,该容器具有

returned

一个subrange的功能,因为我必须构造一个(除非我使用了原始的括号初始化列表,但这并不总是可能的) )会引起复制/移动。
保证的修正解决了所有这些问题。您可以使用只能通过工厂创建的私有构造函数来制作固定类。您可以创建通过公共接口构建固定对象的函数。依此类推。

C ++ 17的行为使固定的非常规类型更加有用和有能力。那不是“概念上正确”吗?

© www.soinside.com 2019 - 2024. All rights reserved.