如何实现类似于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>{});
    }