什么是std :: decay,什么时候应该使用?


185

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


3
它在标准库中使用,例如,将参数传递给线程时。那些需要按值存储,因此您不能存储例如数组。而是存储指针,依此类推。它也是一个模仿功能参数类型调整的元功能。
dyp 2014年

3
decay_t<decltype(...)>是一个很好的组合,看看auto会导致什么。
Marc Glisse 2014年

58
放射性变量?:)
saiarcot895 2014年

7
std :: decay()可以做三件事。1能够将T的数组转换为T *;2.可以删除简历限定词和参考;3.它将函数T转换为T *。例如衰减(void(char))-> void(*)(char)。似乎没有人在答案中提到第三种用法。
r0ng

1
谢天谢地,我们还没有C ++夸克
Wormer,

Answers:


192

<joke>它显然用于将放射性std::atomic类型分解为非放射性类型。</ joke>

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

简而言之,decay<T>::type是身份类型转换,除非T是数组类型或对函数类型的引用。在那些情况下,分别decay<T>::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<T1, T2>将会格式错误。

但这显然导致效率低下。因此,需要使用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_wrapper


“将T1推导为数组类型,然后构造对<T1,T2>将会格式错误。” 这里有什么问题?
卡米诺

6
我明白了,通过这种方式,我们将获得pair <char [4],int>,它只能接受具有4个字符的字符串
camino

@camino我不明白,您是说没有std :: decay的话,该对的第一部分将为四个字符占用4个字节,而不是一个指向char的指针?那是std :: forward的功能吗?阻止它从数组衰减到指针?
斑马鱼

3
@Zebrafish这是数组衰减。例如:template <typename T> void f(T&); f(“ abc”); T是char(&)[4],但是template <typename T> void f(T); f(“ abc”); T是char *; :您还可以在这里找到一个解释stackoverflow.com/questions/7797839/...
卡米诺

68

当处理带有模板类型参数的模板函数时,通常会具有通用参数。通用参数几乎始终是一种或另一种类型的引用。它们也是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


14
我对此不满意。decay是非常激进的,例如,如果将其应用于数组的引用,它将产生一个指针。对于这种元编程恕我直言,它通常过于激进。
dyp 2014年

@dyp,那么“攻击性”又是什么呢?什么是替代品?
Serge Rogatch

5
@SergeRogatch在“通用参数” /通用引用/转发引用的情况下,我只是remove_const_t< remove_reference_t<T> >将其包装在自定义元函数中。
dyp '17

1
甚至在哪里使用param?这是func的论点,但我看不到它在任何地方都被使用
savram

2
@savram:在这些代码段中:不是。我们只检查类型,而不检查值。如果我们删除了参数的名称,那么一切都应该很好,如果不是更好的话。
Mooing Duck
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.