跟我学C++中级篇——STL中decay的应用

一、std::decay

本来是想把它和std::common_type一起分析来,后来发现这两个的内容都不小,所以又分了开来。在前面的文章中专门写过decay的基本说明,这里就不再重复,有兴趣可以看看“跟我学c++中级篇——decay”,言简意赅的说下其功能:
一般它在元编程使用比较多,并且其只能用于模板参数,如果应用于普通参数则编译无法通过。它的基本功能为:
1、它可将数组退化为指针
2、可以删除CV限定符和引用
3、可以将T转为T*,如(void(char))-> void()(char)
基本上来说,如果T为U的数组或者其引用,则类型为U
;如果是函数类型或者其引用则type 是std::add_pointer::type,等同于std::remove_cv::type,也就是前面提到的去除CV限定符和引用。另外在C++14中增加了std::decay_t,省了些流程。

二、应用

在实际的应用场景中,有的时候其实是不需要各种附加条件的或者某些特定的场景,有限定符反而会导致编译错误,最典型的是线程内使用数据时是无法使用数组的,那么使用模板编程时传进去的数组就需要退化为指针。同样,有时候只需要原始的数据类型,在模板编程中就可以通过其进行退化得到原始类型进行操作。
当然,在模板编程中,如果对一些参数进行相似的处理时,也需要通过std::decay 来转换参数类型,从而统一入口进行控制。另外在前面的decltype应用中可以看到,std::decay可以拿到原始类型进行处理。比如返回值只需要原始类型即可,那么就可以用其将得到的类型进行退化。
看下面的例子分析:

#include 
#include 

template <class T> void Test(T&& t) {
	static_assert(std::is_same<typename std::decay<T>::type, int>::value, "equal");
}

int main() {
	double c = 0.0;
	const int& d = (int)c;
	int arr[3] = { 0 };

	Test(c);//这个断言无法通过
	Test(d);
	Test(arr);//这个断言无法通过

	return 0;
}

再看下面的例子:

#include 

template <typename T> int Test1(T &&t) {
  // typedef typename std::decay::type Type;等同下面
  using Type = std::decay_t<decltype(t)>;
  Type data = 100;
  return data;
}

int main() {
  const int &d = 0;
  std::cout << Test1(d) << std::endl;
  return 0;
}

然后再看一个统一限制参数的:

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

int main() {
  const std::string &str = "test";
  char buf[] = "abctest";
  std::pair<std::string, int> p = make_pair("test", 10);
  std::pair<std::string, int> p1 = make_pair(buf, 101);
  // std::pair p2 = std::make_pair(str, 0);
}

三个自定义的make_pair有什么不同?运行一下就明白了。使用引用传入数组或者字符串时,构造pair时就会出现错误。

三、分析

通过上面的例程,基本可以明白了std::decay的用法,但它也有些限制:
1、其无法处理enum类型和union类型,这其实是和无法处理非模板参数一致
2、其只可用于处理模板参数,否则编译器将会报错
3、其对消除指针类型时的应用无效

四、总结

std::decay其实在元编程中应用得还是相当多的,毕竟有的时候宁可错杀一千不可放过一个,安全的控制参数类型才是王道。但仍然需要在实际的场景中仔细的分析应用,不能盲目的不加考虑的使用。有兴趣可以对比的看看std::decay,std::decval和decltype,一定会有收获。

你可能感兴趣的:(C++11,c++)