Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected conversion from 'true'/'false' to some integer types #4358

Open
2 tasks
jboelterintc opened this issue Apr 24, 2024 · 7 comments
Open
2 tasks

Unexpected conversion from 'true'/'false' to some integer types #4358

jboelterintc opened this issue Apr 24, 2024 · 7 comments

Comments

@jboelterintc
Copy link

jboelterintc commented Apr 24, 2024

Description

Converting from "value": true or "value": false behaves unexpectedly and differently for certain integer types.

I was expecting all conversions from a boolean true/false to integer value to fail, however it is stored as a 1 or 0.

Reproduction steps

Given:

template<typename T>
class Value {
public:
    T value;
private:
    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Value<T>, value);
};

This will result in a 1 in value.

auto v = R"({
    "value" : true
})"_json.get<Value<int>>();

Using uint64_t will throw a type_error.

auto v = R"({
    "value" : true
})"_json.get<Value<uint64_t>>();

Expected vs. actual results

I expected all boolean to integer conversions to fail. Instead a true -> 1 and false -> 0 for certain integer values.

Various integer conversions - https://godbolt.org/z/7Wrh6EanW

The uint64_t case is taking the path through get_arithmetic_value

template<typename BasicJsonType>
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
{
    get_arithmetic_value(j, val);
}

The int case is taking the path through

struct from_json_fn
{
    template<typename BasicJsonType, typename T>
    auto operator()(const BasicJsonType& j, T&& val) const
    noexcept(noexcept(from_json(j, std::forward<T>(val))))
    -> decltype(from_json(j, std::forward<T>(val)))
    {
        return from_json(j, std::forward<T>(val));
    }
};

// which calls

template < typename BasicJsonType, typename ArithmeticType,
           enable_if_t <
               std::is_arithmetic<ArithmeticType>::value&&
               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
               int > = 0 >
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
{
//...

        case value_t::boolean:
        {
            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
            break;
        }
//...
}

Minimal code example

https://godbolt.org/z/fs4frqz7G

#include <cassert>
#include <iostream>

#include <nlohmann/json.hpp>

template<typename T>
class Value {
public:
    T value;
private:
    NLOHMANN_DEFINE_TYPE_INTRUSIVE(Value<T>, value);
};

int main() {
    try {
        std::cout << "uint64_t" << std::endl;
        auto v = R"({
            "value" : true
        })"_json.get<Value<uint64_t>>();

        assert(false);
    } catch (const nlohmann::detail::type_error& e) {
        std::cout << e.what() << std::endl;
        std::cout << "ok - exception expected" << std::endl;
    }

    try {
        std::cout << "int" << std::endl;
        auto v = R"({
            "value" : true
        })"_json.get<Value<int>>();

        assert(false);
    } catch (const nlohmann::detail::type_error& e) {
        std::cout << e.what() << std::endl;
        std::cout << "ok - exception expected" << std::endl;
    }
}

Error messages

No response

Compiler and operating system

Latest MSVC & Clang

Library version

3.11.3

Validation

@jshastid
Copy link

I am having the same issue and apologies if I am not understanding this correctly as I am new to C++ and have only just started using this library, but it looks like the integer value is not being considered a basic_json and so is calling the explicit cast from_json. At least the comment above the function leads me to believe this.
// overload for arithmetic types, not chosen for basic_json template arguments
// (BooleanType, etc..); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type?

@thisisamardeep
Copy link

hi i am working on this.Will get something by this weekend.

@amirghaz
Copy link

amirghaz commented Nov 7, 2024

Are you still working on this? I'm planning to look into it.

@amirghaz
Copy link

amirghaz commented Nov 7, 2024

If I'm planning on contributing, is there any guidelines or styles that I need to follow while writing the code? If yes, where can I read about it? Thanks.

@nlohmann
Copy link
Owner

nlohmann commented Nov 7, 2024

See https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md

@nlohmann
Copy link
Owner

@amirghaz Do you need further assistance?

@amirghaz
Copy link

@nlohmann I'm a beginner with this library, so any insight that you have is highly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants