c++boost-json

Override std::tuple serializing functionality in boost::json


boost::json::tag_invoke works fine with structs, but is totally ignored with std::tuple.

Look the next example and mind how the two json arrays are diferent:

Coliru link: https://coliru.stacked-crooked.com/a/e8689f9c523cee2a

#include <iostream>
#include <string>
#include <vector>
#include <boost/json/src.hpp>

using namespace boost::json;

struct Marker
{
    double dist{};
    double lenght;
    int slope{};
};

void tag_invoke( value_from_tag, value& jv, const Marker& marker )
{
    jv = { marker.dist, marker.slope };
}

void tag_invoke( value_from_tag, value& jv, const std::tuple<double, double, int>& marker )
{
    jv = { std::get<0>(marker), std::get<2>(marker) };
}

int main()
{
    boost::json::object json;
    std::vector<Marker> markers1{ {0.0, 100.0, 8}, {250.0, 75.0, -6}, {625.0, 200.0, 11}, {830.0, 55.0, -3} };
    std::vector<std::tuple<double, double, int>> markers2{ {0.0, 100.0, 8}, {250.0, 75.0, -6}, {625.0, 200.0, 11}, {830.0, 55.0, -3} };
        
    json["grad1"] = boost::json::value_from(markers1);
    json["grad2"] = boost::json::value_from(markers2);

    
    std::cout << boost::json::serialize(json) << std::endl;
}

Is there any way to overwrite the std::tuple to boost::json::value to only extract the first and third members?


Solution

  • These functions are found via ADL. With std::tuple<double, double, int>, only overloads in the std:: namespace are searched, which your overload is not in, so it isn't found.

    Boost suggests to either put it where ADL can find it, or in the boost:: namespace if not possible.

    So you can put it in the boost namespace:

    namespace boost {
    void tag_invoke( value_from_tag, value& jv, const std::tuple<double, double, int>& marker )
    {
        jv = { std::get<0>(marker), std::get<2>(marker) };
    }
    }
    

    Or you can associate it with the :: namespace:

    struct MyTuple : std::tuple<double, double, int> {
        using tuple::tuple;
    };
    
    void tag_invoke( value_from_tag, value& jv, const MyTuple& marker )
    {
        jv = { std::get<0>(marker), std::get<2>(marker) };
    }
    
    // ...
    std::vector<MyTuple> markers2{ ... };