0

Why does the following code compile, even though I am passing a std::string object to a explicit constructor which expects a nlohmann::json (to the library) object? My understanding is that std::string won't be implicit converted due to the explicit keyword. Is it possible to change my code so that it will compile successful only when a nlohmann::json is passed?

I use Visual Studio 2019 in Debug Mode with /Wall.

#include <nlohmann/json.hpp>

struct A {
    explicit A(nlohmann::json json) {

    }
};

int main() {
    std::string a = "hello";
    A b(a);
}
DasElias
  • 569
  • 8
  • 19

2 Answers2

1

Why does the following code compile, even though I am passing a std::string object to a explicit constructor which expects a nlohmann::json (to the library) object? My understanding is that std::string won't be implicit converted due to the explicit keyword.

The explicit in the A constructor just means that the A constructor must be called explicitly (which you are). The compiler is allowed to use implicit conversions when passing arguments to the A constructor, unless they use types that are also explicit themselves (which the nlohmann::json constructor is not).

Is it possible to change my code so that it will compile successful only when a nlohmann::json is passed?

You can pass the argument by a non-const reference, preventing the compiler from passing an implicitly created temporary object:

struct A {
    explicit A(nlohmann::json &json) {
    }
};
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

This might be overkill but the following appears to work while also allowing a const-reference as constructor argument:

#include <nlohmann/json.hpp>
#include <type_traits>

struct A {
    template<typename T, typename = std::enable_if_t<std::is_same_v<T, nlohmann::json>>>
    explicit A(const T& json) {

    }
};

int main() {
    const std::string a = "hello";
    // A b(a); // ERROR
    
    const auto json_val = nlohmann::json::parse("{}") ;
    A c {json_val} ;
}