如何利用std::initializer_list让你的初始化函数很骚

好久以前随便瞎转的时候看到一个 c++ 的 json 库支持这样的写法,觉得非常酷,颠覆了c++的三观。
(https://github.com/nlohmann/json)

// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]]
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });

于是就想这种骚操作怎么实现的,现在我终于明白了:

#pragma once
#include "stdafx.h"

class TreeUnit;

class TreeBuilder {
public:
    TreeBuilder(std::initializer_list<TreeUnit> init_list) {

    }
};

class TreeUnit {
public:
    TreeUnit(const char* n) {
        wcout << "from string is called" << endl;
    }
    TreeUnit(Word::WordType word_type) {
        wcout << "from word_type is called" << endl;
    }
};

这里我们用 c 11 支持的新特性 std::initializer_list<TreeUnit> 允许了这样一种初始化方式

TreeUnit treeUnit1, treeUnit2, treeUnit3;
TreeBuilder({ treeUnit1, treeUnit2, treeUnit3 });

如果我们把一个 treeUnitx 换成它的一个构造函数的参数,那也会调用它的构造函数 (converting constructor : https://en.cppreference.com/w/cpp/language/converting_constructor) 构造出TreeUnit

TreeBuilder({ "xxx", Word::SomeType, treeUnit3 }); // SomeType 是 WordType 的一个枚举

这样就达到了看起来“动态类型”的效果,实际上这个std::initializer_list<TreeUnit> 只支持 TreeUnit 的单参数构造函数的类型。

以下代码 Microsoft Visual C++ 2017 编译通过

#pragma once
#include "stdafx.h"

class TreeUnit;

class TreeBuilder {
public:
    TreeBuilder(std::initializer_list<TreeUnit> init_list) {

    }
};

class TreeUnit {
public:
    TreeUnit(const char* n) {
        wcout << "from string is called" << endl;
    }
    TreeUnit(Word::WordType word_type) {
        wcout << "from word_type is called" << endl;
    }
};

...

void test_func_4() {
    TreeBuilder tb1({ "fuk", Word::identifier });
    TreeBuilder tb2({ Word::identifier, "fuk" });
}
from string is called
from word_type is called
from word_type is called
from string is called
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章