如何利用std::initializer_list<T>讓你的初始化函數很騷

好久以前隨便瞎轉的時候看到一個 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章