Home > OS >  Static function to access nlohmann json
Static function to access nlohmann json

Time:12-14

I want to create a class wrapper for nlohmann json library. So I created a class with a static variable nlohmann::json and static function to access it. But when I compile it, the compilers says unresolved external symbol:

unresolved external symbol "private: static class nlohmann::json_abi_v3_11_2::basic_json<class std::map,class std::vector,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,bool,__int64,unsigned __int64,double,class std::allocator,struct nlohmann::json_abi_v3_11_2::adl_serializer,class std::vector<unsigned char,class std::allocator<unsigned char> > > Config::data"

Here is my code:

#pragma once

#include <string>
#include <iostream>
#include <fstream>
#include <filesystem>

#include <nlohmann/json.hpp>

/**
 * @brief Class giving access to the settings of the application.
 * 
 * This class contains static methods that read configuration from file.
 * Only works on Windows OS.
 * 
 * 
 */
class Config
{
private:
    static constexpr const char* path = "Test\\PIDController";
    static constexpr const char* filename = "config.txt";

    static nlohmann::json data;
public:
    /**
     * @brief Check if config exists. If not, create it. Then load config.
     * 
     * Check if the directory of the config file exists. If not, create it.
     * Then check if the config file exists. If not, create it with default
     * configuration.
     * 
     * Use JSON format to store data using JSON for modern C  .
     * [https://github.com/nlohmann/json](https://github.com/nlohmann/json)
     * 
     */
    static void check_default_conf()
    {
        std::filesystem::path file_path = std::filesystem::path(getenv("appdata")) / std::filesystem::path(path) / std::filesystem::path(filename);
        if (!std::filesystem::is_directory(path) || !std::filesystem::exists(file_path))
        {
            bool a = std::filesystem::create_directories(std::filesystem::path(getenv("appdata")) / std::filesystem::path(path));
            std::ofstream of(file_path);
            nlohmann::json default_conf;
            default_conf["target"] = 1e-3f;
            of << std::setw(4) << default_conf;
            of.close();
        }

        // Load conf file
        std::ifstream f(file_path);
        data << f;
        f.close();
    }

    /**
     * @brief Save config file.
     * 
     */
    static void save_conf()
    {
        std::filesystem::path file_path = std::filesystem::path(getenv("appdata")) / std::filesystem::path(path) / std::filesystem::path(filename);

        std::ofstream ofs(file_path);
        ofs << std::setw(4) << data;
        ofs.close();
    }

    /**
     * @brief Get setting matching the given key.
     * 
     * @tparam T Setting type
     * @param key Setting key
     * @return Value of the entry
     */
    template <typename T>
    static T get(const char* key)
    {
        return data[key].get<T>();
    }

    /**
     * @brief Set setting matching the given key.
     * 
     * @tparam T Setting type
     * @param key Setting key
     * @param value Value to set
     * 
     * @par Returns
     *      Nothings.
     */
    template <typename T>
    static void set(const char* key, T value)
    {
        data[key] = value;
    }
};

Do you know where is the problem ? I think my code has a bad pattern but I don't understand where.

I use Visual C 2022 with C 20.

CodePudding user response:

As you can see in the static members documentation, this line in class Config:

static nlohmann::json data;

Is a declaration and not a definition.

In order to solve the problem, you need to add a definition in one of your cpp files (preferably Config.cpp if it exists):

nlohmann::json Config::data;

Since c 17 there is an alernative: you can define data to be an inline static member variable in class Config (which does not require an additional definition):

class Config
{
    // ...
    inline static nlohmann::json data;
    // ...
};
  • Related