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;
// ...
};