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

Using QString as string type #274

Closed
mlutken opened this issue Jun 28, 2016 · 53 comments
Closed

Using QString as string type #274

mlutken opened this issue Jun 28, 2016 · 53 comments

Comments

@mlutken
Copy link

mlutken commented Jun 28, 2016

Hi

It would be very nice if one could do:
using json = nlohmann::basic_json < std::map, std::vector, QString >;

And have everything work.
Right now it seems stringstream are used to stringify etc... So it does not quite compile.

Otherwise I am pretty impressed by the way this library works. Having used hson mostly from PHP, where it's very simple, this is clearly the way to go in C++ :)

-Martin

@nlohmann
Copy link
Owner

Could you please paste the compiler error you got when trying to use QString as string type?

@mlutken
Copy link
Author

mlutken commented Jun 29, 2016

I will be happy too :)

This is a minimal example:

#include <QString>
#include "json.hpp"

//using json = nlohmann::basic_json<std::map, std::vector, std::string>;
using json = nlohmann::basic_json<std::map, std::vector, QString>;

int main()
{
    json j;
    j["attrib1"] = "val1";

    return 0;
}

I get this from gcc:
In file included from ../qjson-test/main.cc:3:0:
../qjson-test/json.hpp: In instantiation of 'nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::value_type& nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::operator [with T = const char; ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::reference = nlohmann::basic_json<std::map, std::vector, QString>&; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::value_type = nlohmann::basic_json<std::map, std::vector, QString>]':
../qjson-test/main.cc:11:16: required from here
../qjson-test/json.hpp:3487:80: error: no matching function for call to 'std::domain_error::domain_error(const QString)'
throw std::domain_error("cannot use operator[] with " + type_name());
^
In file included from /usr/include/c++/5.3.1/system_error:41:0,
from /usr/include/c++/5.3.1/bits/ios_base.h:46,
from /usr/include/c++/5.3.1/ios:42,
from /usr/include/c++/5.3.1/ostream:38,
from /usr/include/c++/5.3.1/iterator:64,
from ../../../../Qt/5.6/gcc_64/include/QtCore/qbytearray.h:46,
from ../../../../Qt/5.6/gcc_64/include/QtCore/qstring.h:42,
from ../../../../Qt/5.6/gcc_64/include/QtCore/QString:1,
from ../qjson-test/main.cc:2:
/usr/include/c++/5.3.1/stdexcept:147:14: note: candidate: std::domain_error::domain_error(const char_)
explicit domain_error(const char_);
^
/usr/include/c++/5.3.1/stdexcept:147:14: note: no known conversion for argument 1 from 'const QString' to 'const char_'
/usr/include/c++/5.3.1/stdexcept:145:14: note: candidate: std::domain_error::domain_error(const string&)
explicit domain_error(const string& __arg);
^
/usr/include/c++/5.3.1/stdexcept:145:14: note: no known conversion for argument 1 from 'const QString' to 'const string& {aka const std::__cxx11::basic_string&}'
/usr/include/c++/5.3.1/stdexcept:142:9: note: candidate: std::domain_error::domain_error(const std::domain_error&)
class domain_error : public logic_error
^
/usr/include/c++/5.3.1/stdexcept:142:9: note: no known conversion for argument 1 from 'const QString' to 'const std::domain_error&'
In file included from ../qjson-test/main.cc:3:0:
../qjson-test/json.hpp: In member function 'nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::value_type& nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::operator [with T = const char; ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::reference = nlohmann::basic_json<std::map, std::vector, QString>&; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::value_type = nlohmann::basic_json<std::map, std::vector, QString>]':
../qjson-test/json.hpp:3489:5: warning: control reaches end of non-void function [-Wreturn-type]
}
^
Makefile:575: recipe for target 'main.o' failed
make: *_* [main.o] Error 1
14:02:22: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project qjson-test (kit: Desktop Qt 5.6.0 GCC 64bit)
When executing step "Make"
14:02:22: Elapsed time: 00:02.

@gregmarr
Copy link
Contributor

    string_t type_name() const noexcept

Since this is a private function that is only used with the std::domain_error() constructor, changing the return type of this function to std::string should be fine. Can you try that and see if there are any other errors?

@nlohmann
Copy link
Owner

@gregmarr How comes that you are always that fast ;)

@gregmarr
Copy link
Contributor

@nlohmann I'm not sure this function can really be noexcept, since it creates a string object, which may need to allocate memory.

@mlutken
Copy link
Author

mlutken commented Jun 30, 2016

I will try and see if that helps :-)

@mlutken
Copy link
Author

mlutken commented Jun 30, 2016

I does help.
Have some trouble with dump(), but will try and explore a little more first :)

@mlutken
Copy link
Author

mlutken commented Jun 30, 2016

Ok, some is working but this program using dump() gives a lot of compiler errors:

using json = nlohmann::basic_json<std::map, std::vector, QString>;

using namespace std;

int main()
{
    json j;
    j["attrib1"] = "val1";
    auto s = j.dump(4);
    return 0;
}

@mlutken
Copy link
Author

mlutken commented Jun 30, 2016

Errors here:

g++ -c -pipe -g -std=gnu++0x -Wall -W -D_REENTRANT -fPIC -DQT_QML_DEBUG -DQT_CORE_LIB -I../qjson-test -I. -I../../../../Qt/5.6/gcc_64/include -I../../../../Qt/5.6/gcc_64/include/QtCore -I. -I../../../../Qt/5.6/gcc_64/mkspecs/linux-g++ -o main.o ../qjson-test/main.cc
In file included from ../qjson-test/main.cc:4:0:
../qjson-test/json.hpp: In instantiation of 'nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::dump(int) const [with ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t = QString]':
../qjson-test/main.cc:15:22:   required from here
../qjson-test/json.hpp:2110:23: error: could not convert 'std::__cxx11::basic_stringstream<_CharT, _Traits, _Alloc>::str() const [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_stringstream<_CharT, _Traits, _Alloc>::__string_type = std::__cxx11::basic_string<char>]()' from 'std::__cxx11::basic_stringstream<char>::__string_type {aka std::__cxx11::basic_string<char>}' to 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}'
        return ss.str();
                    ^
../qjson-test/json.hpp: In instantiation of 'void nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::dump(std::ostream&, bool, unsigned int, unsigned int) const [with ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; std::ostream = std::basic_ostream<char>]':
../qjson-test/json.hpp:2103:17:   required from 'nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::dump(int) const [with ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t = QString]'
../qjson-test/main.cc:15:22:   required from here
../qjson-test/json.hpp:6035:23: error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}')
                    o << string_t(new_indent, ' ') << "\""
                    ^
In file included from /usr/include/c++/5/iostream:39:0,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/ostream:108:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(__ostream_type& (*__pf)(__ostream_type&))
    ^
/usr/include/c++/5/ostream:108:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'std::basic_ostream<char>::__ostream_type& (*)(std::basic_ostream<char>::__ostream_type&) {aka std::basic_ostream<char>& (*)(std::basic_ostream<char>&)}'
/usr/include/c++/5/ostream:117:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>; std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
    operator<<(__ios_type& (*__pf)(__ios_type&))
    ^
/usr/include/c++/5/ostream:117:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'std::basic_ostream<char>::__ios_type& (*)(std::basic_ostream<char>::__ios_type&) {aka std::basic_ios<char>& (*)(std::basic_ios<char>&)}'
/usr/include/c++/5/ostream:127:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(ios_base& (*__pf) (ios_base&))
    ^
/usr/include/c++/5/ostream:127:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'std::ios_base& (*)(std::ios_base&)'
/usr/include/c++/5/ostream:166:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(long __n)
    ^
/usr/include/c++/5/ostream:166:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'long int'
/usr/include/c++/5/ostream:170:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(unsigned long __n)
    ^
/usr/include/c++/5/ostream:170:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'long unsigned int'
/usr/include/c++/5/ostream:174:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(bool __n)
    ^
/usr/include/c++/5/ostream:174:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'bool'
In file included from /usr/include/c++/5/ostream:638:0,
                from /usr/include/c++/5/iostream:39,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/bits/ostream.tcc:91:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char; _Traits = std::char_traits<char>]
    basic_ostream<_CharT, _Traits>::
    ^
/usr/include/c++/5/bits/ostream.tcc:91:5: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'short int'
In file included from /usr/include/c++/5/iostream:39:0,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/ostream:181:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(unsigned short __n)
    ^
/usr/include/c++/5/ostream:181:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'short unsigned int'
In file included from /usr/include/c++/5/ostream:638:0,
                from /usr/include/c++/5/iostream:39,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/bits/ostream.tcc:105:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char; _Traits = std::char_traits<char>]
    basic_ostream<_CharT, _Traits>::
    ^
/usr/include/c++/5/bits/ostream.tcc:105:5: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'int'
In file included from /usr/include/c++/5/iostream:39:0,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/ostream:192:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(unsigned int __n)
    ^
/usr/include/c++/5/ostream:192:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'unsigned int'
/usr/include/c++/5/ostream:201:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(long long __n)
    ^
/usr/include/c++/5/ostream:201:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'long long int'
/usr/include/c++/5/ostream:205:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(unsigned long long __n)
    ^
/usr/include/c++/5/ostream:205:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'long long unsigned int'
/usr/include/c++/5/ostream:220:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(double __f)
    ^
/usr/include/c++/5/ostream:220:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'double'
/usr/include/c++/5/ostream:224:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(float __f)
    ^
/usr/include/c++/5/ostream:224:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'float'
/usr/include/c++/5/ostream:232:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(long double __f)
    ^
/usr/include/c++/5/ostream:232:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'long double'
/usr/include/c++/5/ostream:245:7: note: candidate: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
    operator<<(const void* __p)
    ^
/usr/include/c++/5/ostream:245:7: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'const void*'
In file included from /usr/include/c++/5/ostream:638:0,
                from /usr/include/c++/5/iostream:39,
                from ../qjson-test/main.cc:2:
/usr/include/c++/5/bits/ostream.tcc:119:5: note: candidate: std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char; _Traits = std::char_traits<char>; std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
    basic_ostream<_CharT, _Traits>::
    ^
/usr/include/c++/5/bits/ostream.tcc:119:5: note:   no known conversion for argument 1 from 'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' to 'std::basic_ostream<char>::__streambuf_type* {aka std::basic_streambuf<char>*}'
In file included from /usr/include/c++/5/memory:82:0,
                from ../qjson-test/json.hpp:48,
                from ../qjson-test/main.cc:4:
/usr/include/c++/5/bits/shared_ptr.h:66:5: note: candidate: template<class _Ch, class _Tr, class _Tp, __gnu_cxx::_Lock_policy _Lp> std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__shared_ptr<_Tp, _Lp>&)
    operator<<(std::basic_ostream<_Ch, _Tr>& __os,
    ^
/usr/include/c++/5/bits/shared_ptr.h:66:5: note:   template argument deduction/substitution failed:
In file included from ../qjson-test/main.cc:4:0:
../qjson-test/json.hpp:6035:23: note:   'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' is not derived from 'const std::__shared_ptr<_Tp, _Lp>'
                    o << string_t(new_indent, ' ') << "\""
                    ^

I

..... lots an lots ... more errors ...

In file included from ../qjson-test/main.cc:4:0:
../qjson-test/json.hpp:6095:19: note:   'nlohmann::basic_json<std::map, std::vector, QString>::string_t {aka QString}' is not derived from 'const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>'
                o << string_t("\"") << escape_string(*m_value.string) << "\"";
                ^
In file included from ../../../../Qt/5.6/gcc_64/include/QtCore/QString:1:0,
                from ../qjson-test/main.cc:3:
../../../../Qt/5.6/gcc_64/include/QtCore/qstring.h:1338:28: note: candidate: QDataStream& operator<<(QDataStream&, const QString&)
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QString &);
                            ^
../../../../Qt/5.6/gcc_64/include/QtCore/qstring.h:1338:28: note:   no known conversion for argument 1 from 'std::ostream {aka std::basic_ostream<char>}' to 'QDataStream&'
In file included from ../../../../Qt/5.6/gcc_64/include/QtCore/qstring.h:42:0,
                from ../../../../Qt/5.6/gcc_64/include/QtCore/QString:1,
                from ../qjson-test/main.cc:3:
../../../../Qt/5.6/gcc_64/include/QtCore/qbytearray.h:668:28: note: candidate: QDataStream& operator<<(QDataStream&, const QByteArray&)
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QByteArray &);
                            ^
../../../../Qt/5.6/gcc_64/include/QtCore/qbytearray.h:668:28: note:   no known conversion for argument 1 from 'std::ostream {aka std::basic_ostream<char>}' to 'QDataStream&'
In file included from ../../../../Qt/5.6/gcc_64/include/QtCore/qstring.h:41:0,
                from ../../../../Qt/5.6/gcc_64/include/QtCore/QString:1,
                from ../qjson-test/main.cc:3:
../../../../Qt/5.6/gcc_64/include/QtCore/qchar.h:576:28: note: candidate: QDataStream& operator<<(QDataStream&, QChar)
Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar);
                            ^
../../../../Qt/5.6/gcc_64/include/QtCore/qchar.h:576:28: note:   no known conversion for argument 1 from 'std::ostream {aka std::basic_ostream<char>}' to 'QDataStream&'
make: *** [main.o] Error 1
12:46:19: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project qjson-test (kit: Desktop Qt 5.6.0 GCC 64bit)

@nlohmann
Copy link
Owner

The first error is related to #268: It is implicitly assumed that std::stringstream::str() would return string_t (which is wrong, it's std::string).

Could you try to replace line 2099 with

std::basic_stringstream<typename string_t::value_type,
                        typename string_t::traits_type,
                        typename string_t::allocator_type> ss;

?

@mlutken
Copy link
Author

mlutken commented Jul 1, 2016

I wll try :)

@mlutken
Copy link
Author

mlutken commented Jul 20, 2016

Hi have been on holiday, but will get back to this problem and try you suggestion.
In fact I convenced one of my coworkers that we should push for using this project at our work too. Currently we use picojson.

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

Now it complains that QString does not have a traits_type nested type:
5.6/gcc_64/include/QtCore -I. -I../../../../Qt/5.6/gcc_64/mkspecs/linux-g++ -o main.o ../qjson-test/main.cc
In file included from ../qjson-test/main.cc:4:0:
../qjson-test/json.hpp: In instantiation of 'nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::dump(int) const [with ObjectType = std::map; ArrayType = std::vector; StringType = QString; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; nlohmann::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType>::string_t = QString]':
../qjson-test/main.cc:15:22: required from here
../qjson-test/json.hpp:2102:68: error: no type named 'traits_type' in 'class QString'
typename string_t::allocator_type> ss;
^
../qjson-test/json.hpp:2102:68: error: no type named 'traits_type' in 'class QString'

@nlohmann
Copy link
Owner

It seems as if typename string_t::traits_type is not available if string_t is of type QString. I do no know whether it is possible to create suitable string stream for QStrings.

I thought about changing the dump functions return value to std::string, but this would also not help, because there is no implicit conversion from QString to std::string. I am currently clueless whether this combination can work.

@nlohmann nlohmann added the state: help needed the issue needs help to proceed label Jul 22, 2016
@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

Hi again

Since we really would like to use this at work, I spent today hacking a bit in your code.
Basically I introduced a policy class as a template parameter to abstract the problems away :).

Right now the policy class is itself a template, which is probably not strictly necessary.
It works and I will attach my code so far for you to look at.

My only (small) "problem" is the string literal operators (operator "") you have provided which are very nice indeed. They are defined for a specific typedef of you template and thus conflicts if you use you own.
I tried creating these operators as friends within the template but ran into a gcc bug (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61648).

For now I commented those operators out. A solution could be for you to provide those default typedefs in a separate header file which those wanting the default std::string based version, and the rest of us can just include the main header file and make those typedefs/using and operators ourselves.

I suggest using a diff tool to compare my file with your original. Mine is called jsonqt.hpp, which is your original file with added support for instantiating with QString.

To use your great template with Qt:
using json = nlohmann::basic_json<std::map, std::vector, QString, bool, std::int64_t, std::uint64_t, double, std::allocator, nlohmann::QStringPolicy>;

qjson-test.zip

Regards Martin Lütken

@gregmarr
Copy link
Contributor

Do you know what version of the library you used as your starting point? There's a lot of differences that don't look like they're things that you would have made.

@nlohmann
Copy link
Owner

@mlutken I had a brief look at your code - I am not sure about the overhead of the abstraction, and I am also unsure whether QStrings justify adding another template parameter... Can you comment on that?

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

Well. You already have a lot of template parameters. One of which is the string type. Seems that you can only use it with std:: string types... I really do prefer std:: stuff, but honestly std::string is really not adequate for many applications. QString is probably not perfect either, but it has all the things that std::string is missing like unicode (UTF-8 in particular).

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

This I believe is the version I used as starting point.
json.hpp.zip

@gregmarr
Copy link
Contributor

@nlohmann Is this a bug?

        /// constructor with a given buffer
        explicit lexer(const string_t& s) noexcept
            : m_stream(nullptr), m_buffer(s)
        {
            m_content = reinterpret_cast<const lexer_char_t*>(s.c_str());
            assert(m_content != nullptr);
            m_start = m_cursor = m_content;
            m_limit = m_content + s.size();
        }

s is copied into m_buffer, but then m_content, m_start, and m_cursor are set to point to the passed in string rather than the internal string.

@gregmarr
Copy link
Contributor

There is definitely a performance concern here:

    static StringType toString(const std::stringstream& ss)
    {
        return ss.str();
    }
    static StringType toString(const LexerStringType& str)
    {
        return str;
    }
    static LexerStringType toLexerStringtype(const StringType& str)
    {
        return str;
    }
    static StringType convertStringLitteral(const char* s)
    {
        return reinterpret_cast<const typename StringType::value_type*>(s);
    }

The first three introduce additional copies of the string which are not necessary StringType is std::string (#1) or when LexerStringType and StringType are the same (#2 and #3). Changing them to const & would help there. I'm not sure about #4. I think it's okay.

FYI, you have a typo in a few places, there is only one t in literal.

I can see why you needed additional support in dump to get from the type of std::stringstream::str, and that would probably be needed for string_t = std::wstring as well.

What was the problem when the lexer's m_buffer was QString that it had to be changed to be std::string?

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

Lexer seems to assume const char* is that not correct?
I did not dig too deep into that part, just looked like it would be hard to make it work with QString. QString "char" type is 16 bit and called QChar which in itself is a class.... so using a for ( auto c: string_t ) will iterate those... Might be possible to get to work..

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

#4 is the same your original code so that should execute at same speed. Right ?

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

I don't think there are any performance problems in #1, #2, #3 since those function will be inlined and should completely go away. We could try and make them take and rvale reference and call std::move, but I think it does not make a difference. I will try investigate.

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

The bug you are asking about:
/// constructor with a given buffer
explicit lexer(const string_t& s) noexcept
: m_stream(nullptr),
m_buffer(StringPolicyType::toLexerStringtype(s))
{
m_content = reinterpret_cast<const lexer_char_t*>(m_buffer.c_str());
assert(m_content != nullptr);
m_start = m_cursor = m_content;
m_limit = m_content + m_buffer.size();
}

The above is how the code I sent you should look like.... Is that not OK?

@gregmarr
Copy link
Contributor

gregmarr commented Jul 22, 2016

Yes, that's why I noticed it, pointing it out to @nlohmann in case he didn't notice. Sorry that wasn't clear.

@gregmarr
Copy link
Contributor

I don't think there are any performance problems in #1, #2, #3 since those function will be inlined and should completely go away. We could try and make them take and rvale reference and call std::move, but I think it does not make a difference. I will try investigate.

Okay, so #1-#3 are currently only used in places that are already making a copy, so while it has the potential to be expensive in general, it probably isn't right now. However, adding const & on the output of those functions for the String version wouldn't cost anything.

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

Do you mean like this:
static const StringType& toString(const std::stringstream& ss)
{
return ss.str();
}

?

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

static const StringType& toString(const std::stringstream& ss)
{
return ss.str();
}

This will not work, since then we return a reference to a temporary, which is not good :)

I am a little puzzled why you are so concerned about these function making copies.
I feel pretty sure that with any modern compiler none of these functions will end up being real function calls in the finally generated machine code. They are implicitly declared inline since they are member functions implemented within the "body" of the class definition. The compiler can see everything and will surely inline, use copy elision and make almost all this code "evaporate".

Also even if we were to make a copy of std::string somewhere, even that would be extremely fast in C++11 and forward since move semantics would apply here.

It might be that in C#, Java etc. these functions would indeed be real functions and do indeed make real copies, but I am almost certain they will not do so in C++.

Am I missing something here?

@gregmarr
Copy link
Contributor

Ah, I forgot that stringstream::str returns by value instead of by reference.

I know that I would expect many things to be inlined and copies elided, but there have been many times where things don't always work as one would expect.

I was worried mainly about places where no copy at all was currently done, but it doesn't seem that there are in fact any of those, and there's always a copy being made, so this isn't as big of a deal.

@mlutken
Copy link
Author

mlutken commented Jul 22, 2016

This one:
static const std::string & toString(const std::stringstream& ss)
{
return ss.str();
}

Will make a copy, which will in reality be moved since it's std::string and the returned "copy" is a rvalue reference from which the final destination object can simply steal the internal pointer to the actual string data.

And a function like this:
static LexerStringType toLexerStringtype(const StringType& str)
{
return str;
}
when called like this (remember LexerStringType = StringType = std::string):
auto s2 = toLexerStringtype(s1);

will on any modern compiler end up being 100% equivalant to:
auto s2 = s1;

So no more copies than the one already in the old code in the initializer list of the Lexer constructor:
So we end up with this:
explicit lexer(const string_t& s) noexcept
: m_stream(nullptr),
m_buffer(StringPolicyType::toLexerStringtype(s))
Being the exact same as:
explicit lexer(const string_t& s) noexcept
: m_stream(nullptr),
m_buffer(s)

So no more copies than before. The toLexerStringtype() function call will not exist in the final compiled code.

Is there something about my reasoning that you believe to be wrong ?

@nlohmann
Copy link
Owner

@gregmarr This surely is a bug, and the current test suite did not find it. I added a test case and committed a change to the develop branch.

@gregmarr
Copy link
Contributor

Great. Thanks to @mlutken for finding it.

@nlohmann
Copy link
Owner

My thoughts on this:

  • The code must stay independent from any QT header (I am not sure whether it is possible to define something like template<> class StringPolicy<QString>{ ... }; without providing a type QString).
  • I would really like to avoid an additional template parameter.
  • It would be nice if other string types like std::wstring, std::u16string, or std::u32string could be supported with the same mechanism.

@mlutken
Copy link
Author

mlutken commented Jul 23, 2016

We could simply provide the template that has the QT policy class in a separate header so only people needing this would include it.

We could reduce the overall number of template parameters by putting more into policy classes or just into this one. Seems that at least the string type should be included here. That way we are back to same number as before.

By the way: What other types of string do you support other than std::string ?

@nlohmann
Copy link
Owner

Currently, only std::string is supported, but I'm working to allowing different allocator types.

@nlohmann
Copy link
Owner

nlohmann commented Jul 31, 2016

Here is an old issue #216 where an issue with std::wstring was reported. There is also #20 which reported issues with strings. I think fixing this issue beyond QString could have potential.

@nlohmann nlohmann added the state: please discuss please discuss the issue or vote for your favorite option label Aug 15, 2016
@nlohmann
Copy link
Owner

Any news on this?

@nlohmann
Copy link
Owner

@mlutken Did you have the chance to have a look at this?

@nlohmann
Copy link
Owner

nlohmann commented Nov 8, 2016

Inactive.

@nlohmann nlohmann closed this as completed Nov 8, 2016
@nlohmann nlohmann removed state: help needed the issue needs help to proceed state: please discuss please discuss the issue or vote for your favorite option labels Nov 8, 2016
@mlutken
Copy link
Author

mlutken commented Nov 9, 2016

Hi
It seemed that you were not really interested in taking in the work we had done, so that's why I haven't responded.
I thought I came up with something that could be built on to get a really good solution given some more work, but I felt you didn't really wanted to have those changes :)...

@mlutken
Copy link
Author

mlutken commented Nov 9, 2016

But I might have been wrong...

@nlohmann
Copy link
Owner

nlohmann commented Nov 9, 2016

I did not intent to make the changes myself, but I thought that there was an idea for an implementation which did not rely on QT headers and that would not require to much changes. I'm still open for this, but as there were no reaction for nearly 2 months, I'd rather wanted to close the ticket.

That said, I'm still happy to support more than std::string!

@mlutken
Copy link
Author

mlutken commented Nov 9, 2016

I get that. I understand that you want to compile for non Qt without Qt headers.
I am just unsure how to achieve that without splitting into a least 3 header files:

  • A main template one with the bulk of the code
  • A std:: one with typedefs etc
  • A Qt with similar typedefs and dependency on the QString header

@kainjow
Copy link

kainjow commented May 31, 2017

The readme section "Arbitrary types conversions" seems to indicate that any type can be converted to json, so I was under the impression that this meant I could convert QStrings for my strings. I wrote a little code for this:

inline void to_json(nlohmann::json& j, const QString& q) {
    j = nlohmann::json{q.toStdString()};
}

inline void from_json(const nlohmann::json& j, QString& q) {
    q = QString::fromStdString(j.get<std::string>());
}

however, it appears this results in an array, not a string, using this sample code:

nlohmann::json j{{"extension", QString{".jpg"}}};
std::cout << j.dump() << std::endl;

So after glancing through this thread, I can presume QStrings do not work, and the method in the read me is probably only for objects, not any arbitrary type. If this is so, maybe the read me should be updated to be more clear on what it supports.

@nlohmann
Copy link
Owner

nlohmann commented Jun 1, 2017

@kainjow I think your to_json function should read

inline void to_json(nlohmann::json& j, const QString& q) {
    j = nlohmann::json(q.toStdString());
}

(note the parentheses)

@kainjow
Copy link

kainjow commented Jun 1, 2017

@nlohmann that indeed works, which confuses me, since the examples in the read me use brace initializer.

@nlohmann
Copy link
Owner

nlohmann commented Jun 1, 2017

I think the README has a lot of examples where an object or array is created. There, brace initialization makes sense. But something like json j {"foo"}; will create an array. This should be like this in the README.

@nlohmann
Copy link
Owner

There is already a section in the README:


  • The library supports Unicode input as follows:
    • Only UTF-8 encoded input is supported which is the default encoding for JSON according to RFC 7159.
    • Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors.
    • Unicode noncharacters will not be replaced by the library.
    • Invalid surrogates (e.g., incomplete pairs such as \uDEAD) will yield parse errors.
    • The strings stored in the library are UTF-8 encoded. When using the default string type (std::string), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.

@23W
Copy link

23W commented Feb 19, 2018

@nlohmann
Yes, I saw. Sorry for disturb. I've removed my comment with claim.

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