为什么make_optional会衰减其参数类型?

eca*_*mur 16 c++ optional type-traits c++-standard-library c++14

(可能不是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));
  }
Run Code Online (Sandbox Code Playgroud)

为什么有必要改变类型T(即不仅仅是返回optional<T>),是否有一种哲学(以及实际)理由用于decay转换?

Yak*_*ont 16

一般目的decay是采取类型并将其修改为适合存储.

看一下这些可以decay实现工作的例子,而remove_reference不是:

auto foo( std::string const& s ) {
  if (global_condition)
    return make_optional( s );
  else
    return {};
}
Run Code Online (Sandbox Code Playgroud)

要么

void function() { std::cout << "hello world!\n"; }
auto bar() { return std::make_optional( function ); }
Run Code Online (Sandbox Code Playgroud)

要么

int buff[15];
auto baz() { return std::make_optional( buff ); }
Run Code Online (Sandbox Code Playgroud)

一个optional<int[15]>将是一个非常奇怪的野兽-当像文字,这是治疗的空调风格阵列不守规矩optional确实给它的参数T.

如果你正在数据的副本中,constvolatile源的性质并不重要.而且你只能通过将它们衰减为指针来制作数组和函数的简单副本(不会丢失std::array或类似).(理论上,可以做一些optional<int[15]>工作来完成工作,但这会带来许多额外的复杂因素)

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

如果你想传入T字面意思,make_optional毕竟没有理由使用.


Bri*_*ian 14

这不是新行为make_optional; 实用程序的功能make_pairmake_tuple行为方式相同.我至少可以看到两个理由:

  1. 实际上用未解析的类型实例化模板可能是不合需要的或不可能的.

    • 如果T是一个函数类型,那么,你就是不能在一个类中存储一个函数,句点; 但你可以存储一个函数指针(衰减类型).

    • 如果T是数组类型:由于数组不可复制,因此无法复制生成的类"有缺陷".对于optionalvalue_or成员函数不能在所有被编译,因为它返回T.因此,您根本无法拥有数组类型optional.

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

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

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

    • 对或元组内的类型或可选或任何不应获得cv资格的类型v.也就是说,我们已经x宣布为const int.应该make_optional(x)创造一个optional<const int>?不,不应该; 它应该创造optional<int>.


Jon*_*rdy 6

看看它做了什么decay:

  • 删除引用限定符 - T&T; 没有可选引用,否则你无法重置optional,需要分配.

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

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

  • 否则,删除cv-qualifiers- const intint; 没有可选const值,否则你无法重置optional.