'Template issue with nlohmann::json

Here's my code and the error, and below I'll show some code that works.

#include <iostream>
#include <string>

#include <nlohmann/json.hpp>

using JSON = nlohmann::json;
using std::cout;
using std::endl;
using std::string;

template <class ObjectType>
void dump(const JSON &json) {
    for (auto &[key, value]: json.items()) {
        string foo = value.get<std::string>();
        cout << "Key: " << key;
        cout << " Value: " << foo << endl;
    }
}

int main(int, char **) {
    JSON json;
    json["alpha"] = "beta";
    dump<string>(json);
} 
-$ g++ -std=c++17 Foo.cpp -o Foo && Foo
Foo.cpp: In function ‘void dump(const JSON&)’:
Foo.cpp:14:37: error: expected primary-expression before ‘>’ token
   14 |   string foo = value.get<std::string>();
      |                                     ^
Foo.cpp:14:39: error: expected primary-expression before ‘)’ token
   14 |   string foo = value.get<std::string>();
      |                                       ^

Live demo

If I comment out the template line and change the call in main to dump(json), everything works.

My real problem is actually inside a template class, not a template function, but this is the most simplified version I could create. What I really want is this line:

    ObjectType obj = value.get<ObjectType>();

But that would be the next step.

Does anyone know what I'm doing wrong and how to fix it?



Solution 1:[1]

While it works as-is with MSVC and Clang, in order to get it to compile on GCC without changing the structure or assignment of variables, GCC requires the template disambiguator for dependent types specified in order for it to be correctly parsed.

Snippet:

using JSON = nlohmann::json;

template <class ObjectType>
void dump(const JSON &json) {
    for (auto &[key, value]: json.items()) {
        std::string foo = value.template get<std::string>(); // Here
        std::cout << "Key: " << key;
        std::cout << " Value: " << foo << endl;
    }
}

This is due to value.get<std::string>() being parsed as value.get < ... i.e. value.get followed by the less than operator.

I am wondering whether the reason that this occurs when the function is templated is due to template deduction rules and the existing templating provided for the nlohmann::JSON type which ultimately means the compiler already believes that it has deduced the template type for value.get before parsing the subsequent template specialisation value.get<std::string>.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 C2P1