C++ 1X 新特性
最近写一点代码时候,需要用到Callback和Bind。 protobuf
(github protobuf)的
callback
是挺合适的实现。考虑将来代码发展,想按照项目特有的命名空间和类/变量名称管理,用到了C++ 1X的几个新特性: auto
, decltype
, using
,
Template Variadic Args
.
例如,protobuf实现了一个Closure:
::google::protobuf::Closure;
在项目ds中使用,想放在namespace ds中,可以这么做:
namespace ds { using Closure = ::google::protobuf::Closure; }
同时,protobuf提供了一个NewClosure,namespace ds中可以这么做:
template<typename... Args> inline auto NewClosure(Args&&...args) -> decltype( ::google::protobuf::NewCallback(std::forward<Args>(args)...)) { return ::google::protobuf::NewCallback(std::forward<Args>(args)...); }
在代码中就可以这样使用了:
static size_t simpleCallbackValue = 0; void SimpleCallback() { ++simpleCallbackValue; } bool RetCallback(int x) { return x == 10; } class Square { public: size_t square(size_t n) { return n * n; } }; TEST(TestClosure, Simple) { ds::Closure *cb = ds::NewClosure(SimpleCallback); cb->Run(); ASSERT_EQ(1, simpleCallbackValue); ds::Callback<bool> *cb1 = ds::NewClosure(RetCallback, 5); EXPECT_FALSE(cb1->Run()); cb1 = ds::NewClosure(RetCallback, 10); EXPECT_TRUE(cb1->Run()); Square sx; ds::Callback<size_t> *cb2 = ds::NewPermanentClosure( &sx, &Square::square, (size_t)3); EXPECT_EQ(9, cb2->Run()); }
1 auto
auto
实现自动类型推导。这不同于之前C/C++中表示register或类似的含义。例如:
auto x = 100; // x is a int; auto pf = sqrt; // pf is a function pointer of 'double sqrt(double x)' std::vector<ComplexClass> vec; for (auto it = vec.begin(); vec.end() != it; ++it) { // do stuff }
2 decltype
decltype
用于将变量的类型声明为指定类型。指定的类型可以包含 const
, 引用等修饰。例如:
int i = 3; int &j = i; const int &k = i; decltype(i) d1; // d1 is int decltype(j) d2; // d2 is int& decltype(k) d3; // d3 is const int& decltype( k + 1) d4; // d4 is int
当函数返回类型使用 auto
时,可以用 decltype
后置说明。例如:
template<typename T, typename U> auto f(T t, U u) -> decltype(T*U) { // stuff }
3 using
类似于 typedef
,用于给类或命名空间起别名。
using StrVecIterator = std::vector<std::string>::iterator;
4 可变模板参数
可变模板参数(Variadic template argument)用于创建任意参数的模板函数和类。语法形式是:
template<typename... Args> xfunc(Args... args) { ...; }
Args是一个模板参数包,args是一个函数参数包。Args和args可以是任意符合C++标识符规则的名称。Args与T的区别是,T与一种类型匹配,Args与任意数量(包括0)的类型匹配。
函数内不能使用索引访问args,例如不能使用args[2]。使用方式是利用模板偏特化:
#include <iostream> #include <string> template<typename T> std::ostream& xcout(const T& v) { std::cout << v << std::endl; return std::cout; } template<typename T, typename... Args> std::ostream& xcout(const T& v, Args... args) { std::cout<< v << ", "; xcout(args...); return std::cout; } int main(int argc, char *argv[]) { std::string s("i'm string"); xcout("hello", 100, 3.5, "world", s); xcout(200.5, 30, 'x', s); return 0; }
例如上面代码,输出是:
yanyg@t430:~/test$ g++ cxxargs.cc -std=c++11 yanyg@t430:~/test$ ./a.out hello, 100, 3.5, world, i'm string 200.5, 30, x, i'm string