N4296中
std::decay
的规格留下了以下注释:
[注:这个 行为类似于 左值到右值 (4.1), 数组到指针(4.2),以及 函数到指针 (4.3) 的转换 当左值表达式为 用作右值,但也剥离 类类型中的 cv 限定符 按顺序 更紧密地按价值建模 参数传递。 — 尾注]
在我看来,理想情况下
std::decay
会模型按值参数传递完全,但由于某种原因它没有这样定义。
我认为它可以根据模板参数推导来定义,在这种情况下,还可以定义实现来利用模板参数推导来精确地模型按值参数传递。
template <typename T>
struct decay {
private:
template <typename U>
static U impl(U);
public:
using type = decltype(impl(std::declval<T>()));
};
问题:
std::decay
和按值参数传递有什么区别?std::decay
设计不精确传递按值参数模型吗?std::decay
是在 N2069 中提出的,激励示例是 std::make_pair
返回一对 decay
-ed 类型,这非常接近 std::make_pair
在 C++11 中的实现方式(有一个reference_wrapper
略有例外)。请注意该提案最初没有删除 cv 限定符或顶级参考 - 我认为这只是一个疏忽。
至于它只是简单地models按值参数传递而不是duplicates它的原因,我只能猜测可能是后者限制太多。考虑:
struct A {
A(const A& ) = delete;
};
using T1 = std::decay<A>::type; // T1 == A
using T2 = your_decay<A>::type; // compile error
// use of deleted function A(const A&)
我不能说它是否以这种方式明确指定以允许
decay
-ing 不可复制类型 - 但允许其编译似乎是更好的设计。
正如 Barry 指出的,不可复制对象存在一个问题。为了解决这个问题,我们可以这样写:
template<typename t>
struct decay {
template<typename type> static const type& lref() ;
template<typename u> struct _type_c{ using type = u; };
template<typename u> static constexpr auto impl(const u&) {
return _type_c<u>{};
}
template<typename u, auto sz> static constexpr auto impl(const u(&)[sz]) {
return _type_c<u*>{};
}
template<typename r, typename... p> static constexpr auto impl(r(&)(p...)) {
return _type_c<r(*)(p...)>{};
}
using type = typename decltype(impl(lref<t>()))::type;
};
它适用于 C++14,不需要任何包含。
衰减还需要从数组引用创建指针和从函数引用创建指针。