Yanyg - Software Engineer

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