【问题标题】:What is std::decay and when it should be used?什么是 std::decay 以及何时应该使用它?
【发布时间】:2014-11-02 03:39:36
【问题描述】:

std::decay存在的原因是什么? std::decay在什么情况下有用?

【问题讨论】:

  • 在标准库中使用,例如将参数传递给线程时。那些需要按价值存储,所以你不能存储例如数组。相反,存储一个指针等等。它也是一个模仿函数参数类型调整的元函数。
  • decay_t<decltype(...)> 是一个不错的组合,看看auto 会得出什么结论。
  • 放射性变量? :)
  • std::decay() 可以做三件事。 1 它能够将 T 的数组转换为 T*; 2.可以去掉cv限定符和引用; 3. 将函数 T 转换为 T*。例如衰减(void(char))-> void(*)(char)。似乎没有人在答案中提到第三种用法。
  • 谢天谢地,我们在 c++ 中还没有夸克

标签: c++ c++11 standard-library


【解决方案1】:

在处理采用模板类型参数的模板函数时,您通常具有通用参数。通用参数几乎总是一种或另一种引用。它们也是 const-volatile 合格的。因此,大多数类型特征并不像您期望的那样对它们起作用:

template<class T>
void func(T&& param) {
    if (std::is_same<T,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

int main() {
    int three = 3;
    func(three);  //prints "param is not an int"!!!!
}

http://coliru.stacked-crooked.com/a/24476e60bd906bed

这里的解决方法是使用std::decay:

template<class T>
void func(T&& param) {
    if (std::is_same<typename std::decay<T>::type,int>::value) 
        std::cout << "param is an int\n";
    else 
        std::cout << "param is not an int\n";
}

http://coliru.stacked-crooked.com/a/8cbd0119a28a18bd

【讨论】:

  • 我对此不满意。 decay 非常具有攻击性,例如如果应用于对数组的引用,它会产生一个指针。对于这种元编程恕我直言,它通常过于激进。
  • @SergeRogatch 在“通用参数”/通用引用/转发引用的情况下,我只需要remove_const_t&lt; remove_reference_t&lt;T&gt; &gt;,可能包含在自定义元函数中。
  • 参数在哪里被使用?这是 func 的一个参数,但我没有看到它在任何地方使用
  • @savram:在这些代码中:不是。我们只检查类型,而不是值。如果我们删除参数的名称,一切都应该可以正常工作。
  • @GabrielStaples 是的。根据模板,intconst intint&amp;const int&amp;int&amp;&amp;const int&amp;&amp;volatile intvolatile int&amp;volatile int&amp;&amp;等都是不同的。
【解决方案2】:

它显然是用来将放射性std::atomic类型衰变为非放射性类型。

N2609 是提出std::decay 的论文。论文解释:

简单地说,decay&lt;T&gt;::type 是身份类型转换,除了 如果 T 是数组类型或对函数类型的引用。在那些 在decay&lt;T&gt;::type 产生一个指针或指向函数的指针的情况下, 分别。

激励的例子是 C++03 std::make_pair:

template <class T1, class T2> 
inline pair<T1,T2> make_pair(T1 x, T2 y)
{ 
    return pair<T1,T2>(x, y); 
}

通过值接受其参数以使字符串文字起作用:

std::pair<std::string, int> p = make_pair("foo", 0);

如果它通过引用接受了它的参数,那么T1将被推断为一个数组类型,然后构造一个pair&lt;T1, T2&gt;将是错误的。

但显然这会导致显着的低效率。因此需要decay,应用在按值传递时发生的一组转换,让您获得通过引用获取参数的效率,但仍然获得您的代码使用所需的类型转换字符串字面量、数组类型、函数类型等:

template <class T1, class T2> 
inline pair< typename decay<T1>::type, typename decay<T2>::type > 
make_pair(T1&& x, T2&& y)
{ 
    return pair< typename decay<T1>::type, 
                 typename decay<T2>::type >(std::forward<T1>(x), 
                                            std::forward<T2>(y)); 
}

注意:这不是实际的 C++11 make_pair 实现 - C++11 make_pair 也解开 std::reference_wrappers。

【讨论】:

  • "T1 会被推导出为一个数组类型,然后构造一个pair 将是非良构的。"这里有什么问题?
  • 我明白了,这样我们会得到pair,它只能接受4个字符的字符串
  • @camino 我不明白,你是说如果没有 std::decay 的话,这对的第一部分将占用 4 个字节用于四个字符,而不是一个指向 char 的指针?这就是 std::forward 所做的吗?阻止它从数组衰减到指针?
  • @Zebrafish 是数组衰减。例如:template void f(T&); f("abc"); T 是 char(&)[4],但是 template void f(T); f("abc"); T 是字符*;你也可以在这里找到解释:stackoverflow.com/questions/7797839/…
  • @camino 所以也许保证复制省略也可以解决问题,至少在这种情况下,但当然它还不可用。
猜你喜欢
  • 2018-09-17
  • 2014-03-25
  • 2010-12-10
  • 2011-03-25
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多