如何实现类似于nlohmann/json中的get<T>()?
How to implement a get<T>() similar to that in nlohmann/json?
我正在编写一个 json 库,其用法与 nlohmann/json 相同。但我无法理解 nlohmann 的 get() 函数。所以我自己实现了一个get(),但是我觉得我的方法不是很好,你有什么好的解决方案或者建议吗?
#include <vector>
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
bool func(bool) { return 1; }
int func(int) { return 2; }
double func(double) { return 3; }
string func(string&) { return string("4"); }
vector<int> func(vector<int>&) { return { 5 }; }
map<int, int> func(map<int, int>&) {
map<int, int>a;
a.emplace(6, 6);
return a;
}
template <typename T>
T get() {
static T t;
return func(t);
}
int main() {
cout << get<bool>();
cout << get<int>();
cout << get<double>();
cout << get<string>();
cout << get<vector<int>>()[0];
cout << get<map<int, int>>()[6];
}
你的方法行得通,但是
- 需要默认的可构造类型(因此没有
void
、参考、...),
- 类型“什么都不做”(例如,使用全局互斥锁的 RAII 对象会有问题)。即使是日志也可能很奇怪。
- 你应该关心 conversion/promotion 重载决议(
get<char>
与你的类型不明确,get<void(*)()>
会调用 func(bool)
,但幸运的是也无法编译,因为return 类型)
替代方案:
由于您的类型集似乎有限且不可扩展,
你可能用过if constexpr
:
template <typename T>
T get() {
if constexpr (std::is_same_v<T, bool>) {
return true;
} else if constexpr (std::is_same_v<T, int>) {
return 42;
} else if constexpr (std::is_same_v<T, double>) {
return 4.2;
} else if constexpr (std::is_same_v<T, std::string>) {
return "Hello world";
} else if constexpr (std::is_same_v<T, std::vector<int>>) {
return {4, 8, 15, 16, 23, 42};
} else if constexpr (std::is_same_v<T, std::map<int, int>>) {
return {{1, 2}, {3, 4}};
} else {
static_assert(always_false<T>::value);
}
}
或(完全)专业化:
template <typename T> T get(); // No impl, to specialize
template <> bool get() { return true; }
template <> int get() { return 42; }
template <> double get() { return 4.2; }
template <> std::string get() { return "Hello world"; }
template <> std::vector<int> get() { return {4, 8, 15, 16, 23, 42}; }
template <> std::map<int, int> get() { return {{1, 2}, {3, 4}}; }
重用您的调度想法,但带有标签。 (允许可扩展的类型集和模板实现)
template <typename T> struct tag {};
bool func(tag<bool>) { return true; }
int func(tag<int>) { return 42; }
double func(tag<double>) { return 4.2; }
std::string func(tag<std::string>) { return string("Hello world"); }
std::vector<int> func(tag<std::vector<int>>) { return {4, 8, 15, 16, 23, 42}; }
std::map<int, int> func(tag<std::map<int, int>>) { return {{1, 2}, {3, 4}}; }
#if 0 // Allow extension and template
template <typename T>
UserTemplateType<T> func(tag<UserTemplateType<T>>) { return {}; }
#endif
template <typename T>
T get() {
return func(tag<T>{});
}
我正在编写一个 json 库,其用法与 nlohmann/json 相同。但我无法理解 nlohmann 的 get() 函数。所以我自己实现了一个get(),但是我觉得我的方法不是很好,你有什么好的解决方案或者建议吗?
#include <vector>
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
bool func(bool) { return 1; }
int func(int) { return 2; }
double func(double) { return 3; }
string func(string&) { return string("4"); }
vector<int> func(vector<int>&) { return { 5 }; }
map<int, int> func(map<int, int>&) {
map<int, int>a;
a.emplace(6, 6);
return a;
}
template <typename T>
T get() {
static T t;
return func(t);
}
int main() {
cout << get<bool>();
cout << get<int>();
cout << get<double>();
cout << get<string>();
cout << get<vector<int>>()[0];
cout << get<map<int, int>>()[6];
}
你的方法行得通,但是
- 需要默认的可构造类型(因此没有
void
、参考、...), - 类型“什么都不做”(例如,使用全局互斥锁的 RAII 对象会有问题)。即使是日志也可能很奇怪。
- 你应该关心 conversion/promotion 重载决议(
get<char>
与你的类型不明确,get<void(*)()>
会调用func(bool)
,但幸运的是也无法编译,因为return 类型)
替代方案:
由于您的类型集似乎有限且不可扩展,
你可能用过
if constexpr
:template <typename T> T get() { if constexpr (std::is_same_v<T, bool>) { return true; } else if constexpr (std::is_same_v<T, int>) { return 42; } else if constexpr (std::is_same_v<T, double>) { return 4.2; } else if constexpr (std::is_same_v<T, std::string>) { return "Hello world"; } else if constexpr (std::is_same_v<T, std::vector<int>>) { return {4, 8, 15, 16, 23, 42}; } else if constexpr (std::is_same_v<T, std::map<int, int>>) { return {{1, 2}, {3, 4}}; } else { static_assert(always_false<T>::value); } }
或(完全)专业化:
template <typename T> T get(); // No impl, to specialize template <> bool get() { return true; } template <> int get() { return 42; } template <> double get() { return 4.2; } template <> std::string get() { return "Hello world"; } template <> std::vector<int> get() { return {4, 8, 15, 16, 23, 42}; } template <> std::map<int, int> get() { return {{1, 2}, {3, 4}}; }
重用您的调度想法,但带有标签。 (允许可扩展的类型集和模板实现)
template <typename T> struct tag {}; bool func(tag<bool>) { return true; } int func(tag<int>) { return 42; } double func(tag<double>) { return 4.2; } std::string func(tag<std::string>) { return string("Hello world"); } std::vector<int> func(tag<std::vector<int>>) { return {4, 8, 15, 16, 23, 42}; } std::map<int, int> func(tag<std::map<int, int>>) { return {{1, 2}, {3, 4}}; } #if 0 // Allow extension and template template <typename T> UserTemplateType<T> func(tag<UserTemplateType<T>>) { return {}; } #endif template <typename T> T get() { return func(tag<T>{}); }