Caro的代码使用了大量的 C++11 新特性,这篇博客将对这些出现的特性进行汇总以及记录,我还没怎么用过C++11。
1 关键字:
constexpr: 在编译过程就能确定的常量(计算结果的表达式)
void Run() {
constexpr double kTfBufferCacheTimeInSeconds = 10.;
tf2_ros::Buffer tf_buffer{::ros::Duration(kTfBufferCacheTimeInSeconds)};
tf2_ros::TransformListener tf(tf_buffer);
// ...
}
delete: 禁止使用该函数
// Wires up ROS topics to SLAM. 将ROS主题连接到SLAM。
class Node {
public:
Node(const NodeOptions& node_options,
std::unique_ptr<cartographer::mapping::MapBuilderInterface> map_builder,
tf2_ros::Buffer* tf_buffer);
~Node();
// = delete 禁止使用该函数, delete 可用于任何函数
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
// ...
}
explicit: 阻止隐式转换的发生
class SensorBridge {
public:
explicit SensorBridge(
int num_subdivisions_per_laser_scan, const std::string& tracking_frame,
double lookup_transform_timeout_sec, tf2_ros::Buffer* tf_buffer,
::cartographer::mapping::TrajectoryBuilderInterface* trajectory_builder);
// ...
}
2 用到的C++11的标准函数:
std::move(): 将左值引用转变为右值引用
void Run() {
// ...
// move() 将左值引用转变为右值引用
auto map_builder =
cartographer::common::make_unique<cartographer::mapping::MapBuilder>(
node_options.map_builder_options);
Node node(node_options, std::move(map_builder), &tf_buffer);
if (!FLAGS_load_state_filename.empty()) {
node.LoadState(FLAGS_load_state_filename, FLAGS_load_frozen_state);
}
// ...
}
std::tie()
void Run() {
// ...
NodeOptions node_options;
TrajectoryOptions trajectory_options;
std::tie(node_options, trajectory_options) =
LoadOptions(FLAGS_configuration_directory, FLAGS_configuration_basename);
// ...
}
std::forward_as_tuple()
extrapolators_.emplace(
std::piecewise_construct, std::forward_as_tuple(trajectory_id),
std::forward_as_tuple(
::cartographer::common::FromSeconds(kExtrapolationEstimationTimeSec),
gravity_time_constant));
std::tuple()
set::insert()
std::unique_ptr<>
#include <memory>
std::mt19937 rng(0);
计算随机数的算法
std::prev
std::exp(),std::hypot(),std::abs()
candidate.score *=
std::exp(-common::Pow2(std::hypot(candidate.x, candidate.y) *
options_.translation_delta_cost_weight() +
std::abs(candidate.orientation) *
options_.rotation_delta_cost_weight()));
std::max_element() , std::max()
const Candidate2D& best_candidate =
*std::max_element(candidates.begin(), candidates.end());
// A possible solution.
struct Candidate2D {
Candidate2D(const int init_scan_index, const int init_x_index_offset,
const int init_y_index_offset,
const SearchParameters& search_parameters)
: scan_index(init_scan_index),
x_index_offset(init_x_index_offset),
y_index_offset(init_y_index_offset),
x(-y_index_offset * search_parameters.resolution),
y(-x_index_offset * search_parameters.resolution),
orientation((scan_index - search_parameters.num_angular_perturbations) *
search_parameters.angular_perturbation_step_size) {}
// Index into the rotated scans vector.
int scan_index = 0;
// Linear offset from the initial pose.
int x_index_offset = 0;
int y_index_offset = 0;
// Pose of this Candidate2D relative to the initial pose.
double x = 0.;
double y = 0.;
double orientation = 0.;
// Score, higher is better.
float score = 0.f;
bool operator<(const Candidate2D& other) const { return score < other.score; }
bool operator>(const Candidate2D& other) const { return score > other.score; }
};
std::sort() , std::greater
std::sort(candidates->begin(), candidates->end(), std::greater<Candidate2D>());
std::bind std::placeholders : 占位符
const int trajectory_id = map_builder_->AddTrajectoryBuilder(
expected_sensor_ids, trajectory_options.trajectory_builder_options,
::std::bind(&MapBuilderBridge::OnLocalSlamResult, this,
::std::placeholders::_1, ::std::placeholders::_2,
::std::placeholders::_3, ::std::placeholders::_4,
::std::placeholders::_5));
std::function
// cartographer/cartographer/mapping/trajectory_builder_interface.h
#include<functional>
using LocalSlamResultCallback =
std::function<void(int /* trajectory ID */, common::Time,
transform::Rigid3d /* local pose estimate */,
sensor::RangeData /* in local frame */,
std::unique_ptr<const InsertionResult>)>;
// cartographer/cartographer/mapping/map_builder_interface.h
using LocalSlamResultCallback =
TrajectoryBuilderInterface::LocalSlamResultCallback;
// Creates a new trajectory builder and returns its index.
virtual int AddTrajectoryBuilder(
const std::set<SensorId>& expected_sensor_ids,
const proto::TrajectoryBuilderOptions& trajectory_options,
LocalSlamResultCallback local_slam_result_callback) = 0;
// cartographer/cartographer/mapping/map_builder.h
int AddTrajectoryBuilder(
const std::set<SensorId> &expected_sensor_ids,
const proto::TrajectoryBuilderOptions &trajectory_options,
LocalSlamResultCallback local_slam_result_callback) override;
范围for循环:for (const auto& entry : sensor_bridges_)
std::unordered_map<int, MapBuilderBridge::TrajectoryState>
MapBuilderBridge::GetTrajectoryStates() {
std::unordered_map<int, TrajectoryState> trajectory_states;
for (const auto& entry : sensor_bridges_) {
const int trajectory_id = entry.first;
const SensorBridge& sensor_bridge = *entry.second;
std::shared_ptr<const TrajectoryState::LocalSlamData> local_slam_data;
{
cartographer::common::MutexLocker lock(&mutex_);
if (trajectory_state_data_.count(trajectory_id) == 0) {
continue;
}
local_slam_data = trajectory_state_data_.at(trajectory_id);
}
// Make sure there is a trajectory with 'trajectory_id'.
CHECK_EQ(trajectory_options_.count(trajectory_id), 1);
trajectory_states[trajectory_id] = {
local_slam_data,
map_builder_->pose_graph()->GetLocalToGlobalTransform(trajectory_id),
sensor_bridge.tf_bridge().LookupToTracking(
local_slam_data->time,
trajectory_options_[trajectory_id].published_frame),
trajectory_options_[trajectory_id]};
}
return trajectory_states;
}
// -----------
const int half_width = 1 << (7 - 1);
for (int x_offset : {0, half_width})
{
cout << x_offset << endl;
}
std::chrono
#include <chrono>
// Time at which we last logged the rates of incoming sensor data.
std::chrono::steady_clock::time_point last_logging_time_;
3 容器类相关
3.1 vector
reserve() , emplace_back() , push_back() , back()
std::vector<DiscreteScan2D> DiscretizeScans(
const MapLimits& map_limits, const std::vector<sensor::PointCloud>& scans,
const Eigen::Translation2f& initial_translation) {
std::vector<DiscreteScan2D> discrete_scans;
discrete_scans.reserve(scans.size());
for (const sensor::PointCloud& scan : scans) {
discrete_scans.emplace_back();
discrete_scans.back().reserve(scan.size());
for (const Eigen::Vector3f& point : scan) {
const Eigen::Vector2f translated_point =
Eigen::Affine2f(initial_translation) * point.head<2>();
discrete_scans.back().push_back(
map_limits.GetCellIndex(translated_point));
}
}
return discrete_scans;
}
3.2 map
std::map()
#include <map>
#include <unordered_map>
// These are keyed with 'trajectory_id'.
std::map<int, ::cartographer::mapping::PoseExtrapolator> extrapolators_;
std::unordered_map<int, TrajectorySensorSamplers> sensor_samplers_;
map::emplace() 用于直接构造和插入元素
3.3 set
std::set<>
#include <set>
#include <unordered_set>
// Adds a trajectory for offline processing, i.e. not listening to topics.
int AddOfflineTrajectory(
const std::set<
cartographer::mapping::TrajectoryBuilderInterface::SensorId>&
expected_sensor_ids,
const TrajectoryOptions& options);
// unordered_set
std::unordered_set<std::string> subscribed_topics_;
4 其他:
GUARDED_BY()
MapBuilderBridge map_builder_bridge_ GUARDED_BY(mutex_);
EXCLUDES()
std::unordered_map<int, TrajectoryState> GetTrajectoryStates() EXCLUDES(mutex_);
type_traits: 模板元编程
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
// Implementation of c++14's std::make_unique, taken from
// https://isocpp.org/files/papers/N3656.txt
template <class T>
struct _Unique_if {
typedef std::unique_ptr<T> _Single_object;
};
... : 可变参数模板
template <class T, class... Args>
typename _Unique_if<T>::_Single_object make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
std::remove_extent: 返回数组降低一个维度后的数据类型
template <class T>
typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) {
typedef typename std::remove_extent<T>::type U;
return std::unique_ptr<T>(new U[n]());
}
lamda表达式
// cartographer/mapping/internal/collated_trajectory_builder.cc
sensor_collator_->AddTrajectory(
trajectory_id, expected_sensor_id_strings,
[this](const std::string& sensor_id, std::unique_ptr<sensor::Data> data) {
HandleCollatedSensorData(sensor_id, std::move(data));
});
// cartographer/sensor/collator_interface.h
// Adds a trajectory to produce sorted sensor output for. Calls 'callback'
// for each collated sensor data.
virtual void AddTrajectory(
int trajectory_id,
const std::unordered_set<std::string>& expected_sensor_ids,
const Callback& callback) = 0;
// cartographer/sensor/internal/collator.cc
void Collator::AddTrajectory(
const int trajectory_id,
const std::unordered_set<std::string>& expected_sensor_ids,
const Callback& callback) {
for (const auto& sensor_id : expected_sensor_ids) {
const auto queue_key = QueueKey{trajectory_id, sensor_id};
queue_.AddQueue(queue_key,
[callback, sensor_id](std::unique_ptr<Data> data) {
callback(sensor_id, std::move(data));
});
queue_keys_[trajectory_id].push_back(queue_key);
}
}
// cartographer/sensor/internal/ordered_multi_queue.cc
void OrderedMultiQueue::AddQueue(const QueueKey& queue_key, Callback callback) {
CHECK_EQ(queues_.count(queue_key), 0);
queues_[queue_key].callback = std::move(callback);
}
5 math.h
#include <cmath>
#include <vector>
#include "Eigen/Core"
#include "cartographer/common/port.h"
#include "ceres/ceres.h"
namespace cartographer {
namespace common {
// Clamps 'value' to be in the range ['min', 'max'].
template <typename T>
T Clamp(const T value, const T min, const T max) {
if (value > max) {
return max;
}
if (value < min) {
return min;
}
return value;
}
// Calculates 'base'^'exponent'.
template <typename T>
constexpr T Power(T base, int exponent) {
return (exponent != 0) ? base * Power(base, exponent - 1) : T(1);
}
// Calculates a^2.
template <typename T>
constexpr T Pow2(T a) {
return Power(a, 2);
}
// Converts from degrees to radians.
constexpr double DegToRad(double deg) { return M_PI * deg / 180.; }
// Converts form radians to degrees.
constexpr double RadToDeg(double rad) { return 180. * rad / M_PI; }
// Bring the 'difference' between two angles into [-pi; pi].
template <typename T>
T NormalizeAngleDifference(T difference) {
const T kPi = T(M_PI);
while (difference > kPi) difference -= 2. * kPi;
while (difference < -kPi) difference += 2. * kPi;
return difference;
}
template <typename T>
T atan2(const Eigen::Matrix<T, 2, 1>& vector) {
return ceres::atan2(vector.y(), vector.x());
}
template <typename T>
inline void QuaternionProduct(const double* const z, const T* const w,
T* const zw) {
zw[0] = z[0] * w[0] - z[1] * w[1] - z[2] * w[2] - z[3] * w[3];
zw[1] = z[0] * w[1] + z[1] * w[0] + z[2] * w[3] - z[3] * w[2];
zw[2] = z[0] * w[2] - z[1] * w[3] + z[2] * w[0] + z[3] * w[1];
zw[3] = z[0] * w[3] + z[1] * w[2] - z[2] * w[1] + z[3] * w[0];
}
} // namespace common
} // namespace cartographer