好久以前隨便瞎轉的時候看到一個 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