编译期测试类
前面有几个note说过模板类的偏特化,但是那几个只是简单的利用偏特化的类模板来完成编译器的“if-else”操作,后来又比较深入的了解了下模板元编程(工具书Modern C++ Design),特别是Loki库,看得走火入魔。。。当然也跟着敲了些代码,结果就是把之前刚接触traits时写的signal模板类更新了两个版本,同时也发现些有趣的东西:编译期assertion和编译期函数返类型获取。当然,编译期的东西,大多数时候都是在玩类型。。。
这两个有趣的东西,是C++11开始引入的,所以之前都是自己动手完成。
static_assert 用法很简单
//static_assert(bool constexpr, message);
static_assert(false, "fail"); // 在编译时输出“fail”并结束编译
贴个编译期判断指针的代码
#include <iostream>
#include <vector>
template<typename T>
class type_trait
{
private:
template<typename U> struct ptr
{
typedef U ptr_type;
enum { is_ptr = false, is_mptr = false };
};
template<typename U> struct ptr<U*>
{
typedef U ptr_type;
enum { is_ptr = true, is_mptr = false };
};
template<typename U, typename V>
struct ptr<U V::*>
{
typedef U ptr_type;
enum { is_ptr = true, is_mptr = true };
};
public:
enum { is_ptr = ptr<T>::is_ptr, is_mptr = ptr<T>::is_mptr };
typedef typename ptr<T>::ptr_type pointer_type;
};
struct T
{
void null(){};
};
int main()
{
const bool iter = type_trait<std::vector<int>::iterator>::is_ptr;
std::cout << std::boolalpha << iter << std::endl;
const bool int_ptr = type_trait<int*>::is_ptr;
std::cout << int_ptr << std::endl;
const bool is_mptr = type_trait<void (T::*)()>::is_mptr;
std::cout << is_mptr << std::endl;
}
result_of 用法也很简单
// template<typename> struct result_of;
// template<typename F, typename... Args>
// struct result_of<F(Args...)>;
// 例子
#include <iostream>
#include <functional>
template<typename F, typename... Args>
auto func(F&& f, Args&&... args)
-> std::function<typename std::result_of<F(Args...)>::type()>
{
return std::bind(std::forward<F>(f), std::forward<Args>(args)...);
}
int main()
{
auto f = [](int x, const char* s) -> const char*
{
std::cout << x << s << std::endl;
return s;
};
auto fp = func(f, 1, "test");
std::cout << fp() << std::endl;
}
下面是运行结果
./a.out
1test
test
很明显,result_of
获得了f
的返回类型,并且使用这个类型构成了函数对象std::function<const char*()>
。
当然,如果你不需传入函数的返回值的话就没有必要使用result_of
了。
下面是一个复杂点儿的例子
/*********************************************************
File Name:task.cpp
Author: Abby Cin
Mail: abbytsing@gmail.com
Created Time: Wed 03 Aug 2016 03:46:54 PM CST
**********************************************************/
#include <iostream>
#include <functional>
#include <future>
#include <thread>
#include <queue>
using namespace std;
class Task
{
public:
Task(std::size_t threads = thread::hardware_concurrency())
{
cout << "threads: " << threads << endl;
for(std::size_t i = 0; i < threads; ++i)
{
workers.emplace_back([this]
{
function<void()> task;
for(;;)
{
{
unique_lock<mutex> l(this->task_lock);
task_condtion.wait(l, [this]{ return is_exit || !tasks.empty(); });
if(is_exit && tasks.empty())
return;
task = move(tasks.front());
tasks.pop();
}
task(); // processing task
}
}
);
}
}
~Task()
{
{
unique_lock<mutex> l(task_lock);
is_exit = true;
task_condtion.notify_all();
}
for(auto& x: workers)
x.join();
cout << "task finished.\n";
}
template<typename F, typename... Args>
auto add_task(F&& f, Args&&... args)
-> future<typename result_of<F(Args...)>::type>
{
typedef typename result_of<F(Args...)>::type R;
// make a callable wrapper, using shared_ptr to share task with
// task queue, otherwise, move local variable out of scope may
// cause segfault.
auto task = make_shared<packaged_task<R()>>(bind(forward<F>(f), forward<Args>(args)...));
auto res = task->get_future();
unique_lock<mutex> l(task_lock);
tasks.emplace([task]() { (*task)(); });
return res;
}
void start()
{
unique_lock<mutex> l(task_lock);
task_condtion.notify_all();
}
private:
vector<thread> workers;
mutex task_lock;
condition_variable task_condtion, wait_condition;
bool is_exit = false;
queue<function<void()>> tasks;
};
int main()
{
auto f = [](int x) -> int { return x * 2; };
std::future<int> res1, res2, res3, res4, res5;
{
Task task;
res1 = task.add_task(f, 1);
res2 = task.add_task(f, 2);
res3 = task.add_task(f, 3);
res4 = task.add_task(f, 4);
res5 = task.add_task(f, 5);
task.start();
}
cout << (res1.get() + res2.get() + res3.get() + res4.get() + res5.get()) << endl;
}
结果如下
./a.out
threas: 4
task finished.
30
很明显,res*.get()
的返回类型是通过result_of
推断出来的。当然,这个例子可能会稍微修改下变成真正的线程池。
最后,这些编译期测试的类多数在type_traits
头文件中。
2016-08-04更新
好吧,还是写了个线程池。