好久以前随便瞎转的时候看到一个 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