C++用法记录

无名的命名空间

1
2
3
4
5
6
7
namespace 
{
void fun()
{
//....
}
}

由于命名空间没有名字,在其他文件中显然无法引用,它只在本文件的作用域有效。

若无名命名空间的成员fun函数的作用域为文件A,在文件A中使用无名命名空间的成员,不用也无法用命名空间名限定。

模板里面使用具体的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct NeedChild
{
using Condition = bool (*)(const ASTPtr & node, const ASTPtr & child);

static bool all(const ASTPtr &, const ASTPtr &) { return true; }
static bool none(const ASTPtr &, const ASTPtr &) { return false; }
};

/// Simple matcher for one node type. Use need_child function for complex traversal logic.
template <typename Data_, NeedChild::Condition need_child = NeedChild::all, typename T = ASTPtr>
class OneTypeMatcher
{
public:
using Data = Data_;
using TypeToVisit = typename Data::TypeToVisit;

static bool needChildVisit(const ASTPtr & node, const ASTPtr & child) { return need_child(node, child); }

static void visit(T & ast, Data & data)
{
if (auto * t = typeid_cast<TypeToVisit *>(ast.get()))
data.visit(*t, ast);
}
};

NeedChild这种用法, 目前不知道具体的称谓.

Lambda表达式

基本格式

1
2
3
auto fun = [捕获参数](函数参数){函数体};

auto fun = [](){ std::cout << "Hello Lambda" << std::endl; };

捕获列表:

  • []: 没有使用任何函数对象参数
  • [=]: 函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)
  • [&]: 函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)
  • [this]: 函数体内可以使用Lambda所在类中的成员变量
  • [a]: 将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符
  • [&a]: 将a按引用进行传递
  • [a, &b]: 将a按值进行传递,b按引用进行传递
  • [=,&a, &b]: 除a和b按引用进行传递外,其他参数都按值进行传递
  • [&, a, b]: 除a和b按值进行传递外,其他参数都按引用进行传递

Lambda是const函数, 内联展开, 没有实际地址

::*的用法

Clickhouse有这么的一个结构体

1
2
3
4
5
6
7
struct Optimization
{
using Function = size_t (*)(QueryPlan::Node *, QueryPlan::Nodes &);
const Function apply = nullptr;
const char * name = "";
const bool QueryPlanOptimizationSettings::* const is_enabled{};
};

is_enabled is a pointer to a member. It means that it points to an bool member variable that is declared in the class QueryPlanOptimizationSettings.

参考

类型关键字

1
2
3
auto:自动类型推导,声明变量时必须赋初值。类型由右值的决定
decltype :声明表达式类型,声明变量时时不必赋初值。类型由编译器根据表达式自动推导
typeid:运行时类型信息(RTTi),不能用来声明变量

用法

1
2
3
4
5
6
7
8
9
int a = 0;
auto b = a;
decltype(b) c;
if ((typeid(a) == typeid(b))
&& (typeid(a) == typeid(c))
&& (typeid(b) == typeid(c))) { //true

cout << "true" << endl;
}

强制类型转化

四种类型转化关键字

  1. static_cast:

    任何编写程序时能够明确的类型转换都可以使用static_cast,由于不提供运行时的检查,需要在编写程序时确认转换的安全性。

  2. dynamic_cast

    dynamic_cast会在运行时检查类型转换是否合法,具有一定的安全性;上行转换和static_cast没有区别,都是安全的;下行转换时,dynamic_cast会检查转换的类型,相比static_cast更安全

  3. const_cast

    常量指针被转换成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引,并且仍然引用原来的对象。

  4. reinterpret_cast
    非常激进的指针类型转换,在编译期完成,可以转换任何类型的指针,所以极不安全。非极端情况不要使用。

智能指针无法使用上面的关键字, 有专门的用法:

1
2
3
static_pointer_cast
dynamic_pointer_cast
const_pointer_cast

模板的显示实例化

1
2
3
4
5
6
7
8
9
10
template<class T>
void swap(T &a, T &b )
{
T temp;
temp = a;
a = b;
b = temp;
};

template void swap<int>(int &a, int & b);