Cartographer 所用到的 google库和C++11 新特性

Caro的代码使用了大量的google库和 C++11 新特性,这篇博客将对这些出现的特性进行汇总以及记录。

C++11是什么? 参考链接c++11百度百科

C++11标准是 ISO/IEC 14882:2011 - Information technology – Programming languages – C++ 的简称

C++11标准由国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C++标准委员会(ISO/IEC JTC1/SC22/WG21)于2011年8月12日公布 [2] ,并于2011年9月出版。

2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正)。此次标准为C++98发布后13年来第一次重大修正。

1、google库

1.1 gflags

gflags是什么
gflags是google的一个开源的处理命令行参数的库,使用c++开发,具备python接口,可以替代getopt。
gflags使用起来比getopt方便,但是不支持参数的简写(例如getopt支持–list缩写成-l,gflags不支持)

//使用flags需要包含头文件
#include <gflags/gflags.h>

//gflags主要支持的参数类型包括bool,int32, int64, uint64, double, string等,定 义参数通过DEFINE_type宏实现,如下所示,分别定义了一个bool和一个string类型的参数, 该宏的三个参数含义分别为命令行参数名,参数默认值,以及参数的帮助信息:

eg:

DEFINE_bool(big_menu, true, "Include 'advanced' options in the menu listing"); 
DEFINE_string(languages, "english,french,german", 
                 "comma-separated list of languages to offer in the 'lang' menu");

1.2 Abseil(参考链接:link.

cartographer涉及的代码块案例:

auto file_resolver =
      absl::make_unique<cartographer::common::ConfigurationFileResolver>(
          std::vector<std::string>{configuration_directory});

Abseil已在Google历经十多年的开发,它的目的是为Google编程人员在各种项目上的工作需求提供支持,这些项目包括Protocol Buffers、gRPC和TensorFlow等

C++ 标准库的扩充。有些是弥补标准库缺失的功能,有些是根据内部特殊需求,提供了替代方案。
Abseil 目前遵循 C++11,计划到 2019 年,以 C++14 为基础语言版本。
目前代码已经放在 GitHub 上:https://github.com/abseil/abseil-cpp ,基于 Apache 许可证开源。

2、关键字:

2.1 constexpr

constexpr 说明符声明可以在编译时求得函数或变量的值.

cartographer涉及的代码块案例:

void Run() {
  constexpr double kTfBufferCacheTimeInSeconds = 10.;
  tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
  tf2_ros::TransformListener tf(tf_buffer);
  // ...
}

参考链接: constexpr 说明符(C++11 起).

2.2 std::tie

cartographer涉及的代码块案例:

void Run() {
  // ...
  NodeOptions node_options;
  TrajectoryOptions trajectory_options;
  std::tie(node_options, trajectory_options) =
      LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
   // ...

std::tie会将变量的引用整合成一个tuple,从而实现批量赋值。

tuple即元组,可以理解为pair的扩展,可以用来将不同类型的元素存放在一起,常用于函数的多返回值

tuple定义与初始化:
tuple可以使用初始化列表进行赋值。

tuple<int,double,string> t3 = {1, 2.0, "3"};

tuple访问
可以使用get<常量表达式>(tuple_name)来访问或修改tuple的元素(返回引用)

   get<0>(t3) = 4;
   cout << get<1>(t3) << endl;

会输出2

std::tie会将变量的引用整合成一个tuple,从而实现批量赋值。

int i; double d; string s;
tie(i, d, s) = t3;

cout << i << " " << d << " " << s << endl;

会输出4 2 3

还可以使用std::ignore忽略某些tuple中的某些返回值,如

tie(i, ignore, s) = t3;

需要注意的是,tie无法直接从初始化列表获得值,比如下面第5行会编译错误。

int i; double d; string s;
tuple<int,double,string> t3 = {1, 2.0, "3"};
tie(i, d, s) = t3;
t3 = {1, 2.0, "3"};
tie(i, d, s) = {1, 2.0, "3"}

2.3 std::move(参考链接:link.

cartographer涉及的代码块案例:

  cartographer::common::LuaParameterDictionary lua_parameter_dictionary(
      code, std::move(file_resolver));

在C++11中,标准库在中提供了一个有用的函数std::move,std::move并不能移动任何东西,它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值,以用于移动语义。从实现上讲,std::move基本等同于一个类型转换:static_cast<T&&>(lvalue);

std::move函数可以以非常简单的方式将左值引用转换为右值引用。

  1. C++ 标准库使用比如vector::push_back 等这类函数时,会对参数的对象进行复制,连数据也会复制.这就会造成对象内存的额外创建, 本来原意是想把参数push_back进去就行了,通过std::move,可以避免不必要的拷贝操作。
  2. std::move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存的搬迁或者内存拷贝所以可以提高利用效率,改善性能.。
  3. 对指针类型的标准库对象并不需要这么做.

用法:

原lvalue值被moved from之后值被转移,所以为空字符串.

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;
    //调用常规的拷贝构造函数,新建字符数组,拷贝数据
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";
    //调用移动构造函数,掏空str,掏空后,最好不要使用str
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";
    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
   return;

输出:

After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"

2.4 auto(参考链接:link

cartographer涉及的代码块案例:

auto file_resolver =
      absl::make_unique<cartographer::common::ConfigurationFileResolver>(
          std::vector<std::string>{configuration_directory});

auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型.

   int a = 10;
   auto au_a = a;//自动类型推断,au_a为int类型

上面举的这个例子很简单,在真正编程的时候也不建议这样来使用auto,直接写出变量的类型更加清晰易懂。

下面列举auto关键字的正确用法。

用于代替冗长复杂、变量使用范围专一的变量声明。

想象一下在没有auto的时候,我们操作标准库时经常需要这样:

#include<string>
#include<vector>
int main()
{
    std::vector<std::string> vs;
    for (std::vector<std::string>::iterator i = vs.begin(); i != vs.end(); i++)
    {
        //...
    }
}

这样看代码写代码实在烦得很。有人可能会说为何不直接使用using namespace std,这样代码可以短一点。实际上这不是该建议的方法(C++Primer对此有相关叙述)。使用auto能简化代码:

#include<string>
#include<vector>
int main()
{
    std::vector<std::string> vs;
    for (auto i = vs.begin(); i != vs.end(); i++)
    {
        //..
    }
}

for循环中的i将在编译时自动推导其类型,而不用我们显式去定义那长长的一串。

在定义模板函数时,用于声明依赖模板参数的变量类型。

template <typename _Tx,typename _Ty>
void Multiply(_Tx x, _Ty y)
{
    auto v = x*y;
    std::cout << v;
}

若不使用auto变量来声明v,那这个函数就难定义啦,不到编译的时候,谁知道x*y的真正类型是什么呢?

模板函数依赖于模板参数的返回值

template <typename _Tx, typename _Ty>
auto multiply(_Tx x, _Ty y)->decltype(x*y)
{
    return x*y;
}

当模板函数的返回值依赖于模板的参数时,我们依旧无法在编译代码前确定模板参数的类型,故也无从知道返回值的类型,这时我们可以使用auto。格式如上所示。

decltype操作符用于查询表达式的数据类型,也是C++11标准引入的新的运算符,其目的也是解决泛型编程中有些类型由模板参数决定,而难以表示它的问题。

auto在这里的作用也称为返回值占位,它只是为函数返回值占了一个位置,真正的返回值是后面的decltype(_Tx*_Ty)。为何要将返回值后置呢?如果没有后置,则函数声明时为:

decltype(x*y)multiply(_Tx x, _Ty y)

而此时x,y还没声明呢,编译无法通过

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值