目录
参考来源:博客园-qicosmos
[参考来源:深入应用 C++ 11 代码优化与工程级应用-第3章]
一、可变参数
1.1 模板函数的展开
1.1.1 递归展开
// 使用std::enable_if_t 选择合适的重载函数
template <size_t I = 0, typename Tuple>
typename std::enable_if_t<I == std::tuple_size<Tuple>::value> PrintTp(Tuple t) {} // 相等时, 终止
template <size_t I = 0, typename Tuple>
typename std::enable_if_t<I < std::tuple_size<Tuple>::value> PrintTp(Tuple t)
{
std::cout << std::get<I>(t) << "\n";
PrintTp<I + 1>(t);
}
template <typename... Args>
void Print(Args... args)
{
PrintTp(std::make_tuple(args...));
}
int main()
{
Print("hello world!", 666);
return 0;
}
1.1.2 逗号表达式和初始化列表展开
template <typename... Args>
void Print(Args... args)
{
std::initializer_list<int> { ([&] {
std::cout << args << "\n";
}(), 0)...};
}
int main()
{
Print("hello world!", 666);
/* 展开为:
std::initializer_list<int> {
([&] { std::cout << "hello world!" << "\n";}(), 0),
([&] { std::cout << 666 << "\n";}(), 0)
}
等价于: std::initializer_list<int> {0, 0};
*/
return 0;
}
1.2 模板类
可变参数模板类的参数包需要通过模板特化或继承的方式展开
1.1.1 递归+特化
template <typename First, typename... Rest>
struct Sum { // 类的定义
enum { value = Sum<First>::value + Sum<Rest...>::value };
};
template <typename Last>
struct Sum<Last> { // 递归终止类
enum { value = sizeof(Last) };
};
// 或者: template <> struct Sum { enum { value = 0}; };
template <typename First, typename... Rest>
struct Sum : std::integral_constant<int,
Sum<First>::value + Sum<Rest...>::value> {};
template <typename Last>
struct Sum<Last> : std::integral_constant<int, sizeof(Last)> {};
int main()
{
std::cout << Sum<int, double, char>::size; // 13
return 0;
}
1.3 消除重复代码
struct A { A(int) { puts("A(int)"); } };
struct B { B(int, double) { puts("B(int, double)"); } };
// 工厂函数--无需 typename T1, typename T2, ...
template <typename T, typename... Args>
T* Instance(Args&&... args)
{
// 使用完美转发消除值拷贝的损耗
return new T(std::forward<Args>(args)...);
}
int main()
{
A* pa = Instance<A>(1);
B* pb = Instance<B>(1, 2.);
return 0;
}
二、获取可调用对象返回类型的 traits
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
class Person {
public:
Person(int age, std::string name) : mAge(age), mName(std::move(name)) {}
[[nodiscard]] int GetAge() const
{
return mAge;
}
[[nodiscard]] std::string GetName() const
{
return mName;
}
private:
int mAge;
std::string mName;
};
template <typename Fn>
auto GroupByPost(const std::vector<Person>& vt, Fn&& keySelector) ->
std::multimap<decltype(keySelector(*static_cast<Person*>(nullptr))), Person>
{
// 也可以前置:
// std::multimap<decltype(Fn(*((Person*)nullptr))), Person>
// std::multimap<decltype(Fn((Person&)nulltype)), Person> // 现在无法使用
using KeyType = decltype(keySelector(*static_cast<Person*>(nullptr)));
std::multimap<KeyType, Person> m;
std::for_each(vt.begin(), vt.end(), [&] (const auto& person) {
m.insert(std::make_pair(keySelector(person), person));
});
return m;
}
template <typename Fn>
std::multimap<std::result_of_t<Fn(Person)>, Person>
GroupBy(std::vector<Person>& vt, Fn&& keySelector)
{
using KeyType = std::result_of_t<Fn(Person)>;
std::multimap<KeyType, Person> m;
std::for_each(vt.begin(), vt.end(), [&] (const auto& person) {
m.insert(std::make_pair(keySelector(person), person));
});
return m;
}
template<typename R>
class Range {
public:
using RValueType = typename R::value_type;
Range() = default;
~Range() = default;
// 实现容器内任意类型
template <typename Container, typename KeyFn, typename ValueFn>
std::multimap<std::result_of_t<KeyFn(RValueType)>, std::result_of_t<ValueFn(RValueType)>>
GroupBy(Container& ct, KeyFn&& keySelector, ValueFn&& ValueSelector)
{
using KeyType = std::result_of_t<KeyFn(Person)>;
using ValueType = std::result_of_t<ValueFn(Person)>;
std::multimap<KeyType, ValueType> m;
std::for_each(ct.begin(), ct.end(), [&] (const auto& person) {
m.insert(std::make_pair(keySelector(person), ValueSelector(person)));
});
return m;
}
static Range<R>& GetInstance()
{
static Range<R> range;
return range;
}
};
template <typename T, size_t N>
void Print(T t)
{
if constexpr (N <= 1) {
std::cout << std::get<N - 1>(t);
return;
} else {
Print<T, N - 1>(t);
std::cout << ", " << std::get<N - 1>(t);
}
}
template <typename... Args>
void Print(const std::tuple<Args...>& t)
{
std::cout << "(";
Print<decltype(t), sizeof...(Args)>(t);
std::cout << ")";
}
int main()
{
Person p1(10, "Bob");
Person p2(10, "LiMei");
Person p3(26, "Martin");
std::vector vt{p1, p2, p3};
auto gbp = GroupByPost(vt, [] (const auto& item) {
return item.GetName();
});
std::for_each(gbp.begin(), gbp.end(), [] (const auto& item) {
std::cout << item.first << "\t" << " age = "
<< item.second.GetAge() << " name = " << item.second.GetName() << "\n";
});
auto gb = GroupBy(vt, [] (const auto& item) {
return item.GetAge();
});
std::for_each(gb.begin(), gb.end(), [] (const auto& item) {
std::cout << item.first << "\t" << " age = "
<< item.second.GetAge() << " name = " << item.second.GetName() << "\n";
});
auto rgb = Range<decltype(vt)>::GetInstance().GroupBy(vt, [] (const Person& person) {
// 不能使用 tie: connot bind non-const lvalue reference of type
return std::make_tuple(person.GetName(), person.GetAge());
}, [] (const Person& person) {
return std::make_tuple(person.GetName());
});
std::for_each(rgb.begin(), rgb.end(), [] (const auto& item) {
Print(item.first);
std::cout << ":";
Print(item.second);
std::cout << "\n";
});
}