欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c++11 decay/decltype/declval

程序员文章站 2022-05-27 22:51:44
...

 

1. decay

std::decay对类型进行退化处理。

a. T为数组U或数组U引用,则type为U*.

b. T为函数时,则type为std::add_pointer<F>::type.

c. 其它类型则移除cv限定符(const和volatile),则type为std::remove_cv<std::remove_reference<T>::type>::type.

decay_equiv<const int&, int>::value // true
decay_equiv<int[2], int*>::value	// true
decay_equiv<int(int), int(*)(int)>::value // true

 

 

2. decltype

delctype 可以在编译期内推导表达式所得值的类型。

 

template<typename T1, typename T2>  
void sum(T1 &t1, T2 &t2, decltype(t1 + t2) &s)
{  
	s = t1 + t2;  
}

template<typename T1, typename T2>  
auto sum(T1 &t1, T2 &t2) ->decltype(t1 + t2))
{  
	return t1 + t2;  
} 

int hash(char*);
map<string, decltype(hash(nullptr))> mm;	// 动态指定hash()返回类型,方便后续维护

 

 

3. declval

std::declval 返回对象的右值引用,不管对象是否有构造函数,一般配合decltype使用。

 

struct MyOb
{
	MyObj1(){ cout << "Constuctor" << endl; }
	int foo() const { return 1; }
};

struct MyObj
{
	MyObj(const MyObj&){}
	int foo() const { return 1; }
};

void test()
{
	decltype(MyOb().foo()) n0 = 1;					// ok, 构造函数不会调用
	decltype(MyObj().foo()) n1 = 1;					// 编译错误,MyObj没有默认构造函数
	decltype(std::declval<MyObj>().foo()) n2 = 2;	// ok, int
	cout << typeid(n2).name() << endl;				// i
}

 

 

3. 元素分组实例

定义Person结构,如按照人物姓名,年龄,城市各个不同的维度进行分组,可很快写出以下版本:

 

struct Person  
{  
	string name;  
	int age;  
	string city;  
};

template<typename T, typename Fn>  
multimap<T, Person> GroupBy(const vector<Person>& vt, const Fn& keyfn)  
{  
	multimap<T, Person> map;  
	std::for_each(vt.begin(), vt.end(), [&map, $keyfn](const Person& person)  
	{  
		map.insert({keyfn(person), person}); // keyfn返回值为key
	});  

	return map;  
}

 

 

传统方式通过显式指定key类型,可通过c++11语法推导key类型:

方式一:declval

 

multimap<decltype(declval<Fn>()(declval<Person>())), Person> mp;

 

方式二. result_of 

 

multimap<typename std::result_of<Fn(Person)>::type, Person> mp;

 

 

方式二使用更加简洁,用result_of改写上述版本:

typedef typename vector<Person>::value_type value_type; 

template<typename Fn>  
multimap<typename result_of<Fn(value_type)>::type, value_type> GroupBy(const vector<Person>& vt, const Fn& keyfn)  
{  
	typedef typename result_of<Fn(value_type)>::type keytype;   
  	multimap<keytype, value_type> map;

	std::for_each(vt.begin(), vt.end(), [&map, &keyfn](const Person& person)  
	{  
		map.insert({keyfn(person), person});
	});  

	return map;  
}


// 调用
multimap<int, Person> mp = GroupBy(v, [](const Person &p)
{ 
	return p.age; 
});

 

cppreference可能实现:

// Minimal C++11 implementation:
template <class> struct result_of;
template <class F, class... ArgTypes>
struct result_of<F(ArgTypes...)> {
    using type = decltype(detail::INVOKE(std::declval<F>(), std::declval<ArgTypes>()...));
};

 

 

参考链接:

https://en.cppreference.com/w/cpp/types/result_of

https://www.cnblogs.com/anzhsoft/p/3602984.html