为什么make_optial会衰减其参数类型

Why does make_optional decay its argument type?

本文关键字:参数 类型 衰减 make optial 为什么      更新时间:2023-10-16

(可能不是C++14,可能是库TS(设施make_optional(在n3672中(定义为:

template <class T>
  constexpr optional<typename decay<T>::type> make_optional(T&& v) {
    return optional<typename decay<T>::type>(std::forward<T>(v));
  }

为什么有必要转换类型T(即不只是返回optional<T>(,是否有哲学(以及实践(理由专门使用decay作为转换?

decay的一个通用目的是获取一个类型并将其修改为适合存储。

看看这些例子,decay可以工作,而remove_reference不会:

auto foo( std::string const& s ) {
  if (global_condition)
    return make_optional( s );
  else
    return {};
}

void function() { std::cout << "hello world!n"; }
auto bar() { return std::make_optional( function ); }

int buff[15];
auto baz() { return std::make_optional( buff ); }

optional<int[15]>将是一个非常奇怪的野兽——C风格的数组在像文字一样处理时表现不佳,这就是optional对其参数T所做的。

如果要复制数据,则源的constvolatile性质无关紧要。并且,您只能通过将数组和函数衰减为指针来制作数组和函数的简单副本(而不需要回退到std::array或类似内容(。(理论上,optional<int[15]>可以工作,但这会带来很多额外的复杂性(

所以std::decay解决了所有这些问题,并且不会真正引起问题,只要允许make_optional推导其参数的类型,而不是从字面上传递T

如果你想从字面上传递一个T,那么根本没有理由使用make_optional

这不是make_optional的新行为;实用函数CCD_ 21和CCD_。我可以看到至少两个这样做的原因:

  1. 使用未更改的类型实际实例化模板可能是不可取的,也可能是不可能的。

    • 如果T是一个函数类型,那么,您就不能将函数存储在类、句点中;但是可以存储函数指针(衰退类型(。

    • 如果T是一个数组类型:由于数组是不可复制赋值的,因此生成的类将是"有缺陷的",因为它无法复制。对于optional,根本无法编译value_or成员函数,因为它返回T。因此,optional中根本不能有数组类型。

  2. 不衰减类型可能会导致意外行为。

    • 如果参数是字符串文字,我个人希望包含的类型是const char*,而不是const char [n]。这种衰变发生在大多数地方,为什么不在这里呢?

    • 如果v是左值,则T将被推导为左值参考类型。我真的想要一个包含引用的对吗,例如,仅仅因为其中一个参数是左值?当然不是。

    • 对或元组内的类型或可选类型或其他不应获得v的cv资格的类型。也就是说,假设我们将x声明为const intmake_optional(x)应该创建optional<const int>吗?不,不应该;它应该创建CCD_ 38。

看看decay的作用:

  • 删除引用限定符--T&T;没有可选的引用,否则您无法重新放置optional,它需要是可分配的。

  • 对于数组类型,删除范围--T[42]T*;可选的固定范围数组没有那么有用,因为每个数组大小都有不同的类型,并且不能直接按值传递数组类型,这是valuevalue_or成员函数工作所必需的。

  • 对于函数类型,添加指针--T(U)T(*)(U);由于类似的原因,没有可选的函数引用。

  • 否则,删除cv限定符--const intint;没有可选的const值,否则无法重新设置optional