Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to insert a tuple into a map?

I was writing a zip_iterator (for fun/academic/"oh noes Boost is evil we don't want it" reasons) and one of the use cases I envisioned is zipping two vectors together into another container, such as a map. This worked on Clang with libc++, but failed unexpectedly on MSVC2017 and GCC 7.2. I reduced the problem to this code:

#include <iterator>
#include <map>
#include <tuple>

int main()
{
    std::map<int, double> map;

    auto it = std::inserter(map, map.begin());

    it = std::make_tuple(1, 1.);
}

Working demo for Clang here, broken demo's for GCC here and MSVC here.

This makes elegant use of my zip_iterator not work:

std::copy(zip_begin(ints, doubles), zip_end(ints, doubles), std::inserter(int_double_map, int_double_map.begin()));

See here for the full code of that zip_iterator as I have it now.

I expect this to work because a tuple is a 2-pair element and one should be constructible from the other. If I try to find a generic pair(tuple) constructor, or a tuple to pair implicit conversion, I can't seem to find one. So then the question becomes: why does it work on Clang/libc++ at all?

Note: I can't just shove an std::make_pair in there, because, well, it's generic code.

A possible workaround would be to special-case the two-iterator case to produce a pair instead of a tuple. Seems ugly, but doable. I'd rather avoid that if at all possible.

like image 750
rubenvb Avatar asked Nov 28 '25 01:11

rubenvb


1 Answers

and one should be constructible from the other

  • std::pair<T, U> does not define any implicit constructor from std::tuple<T, U>.

  • Similarly, std::tuple<T, U> does not define any implicit conversion operator to std::pair<T, U>.

I think Clang (libc++) is incorrect here, and that GCC and MSVC are correct.


Seems ugly, but doable

It's not too bad:

template <typename... Ts> 
auto make_thing(Ts&&... xs)
{
    if constexpr(sizeof...(xs) == 2)) 
    { 
        return std::make_pair(std::forward<Ts>(xs)...);
    }
    else
    {
        return std::make_tuple(std::forward<Ts>(xs)...);
    } 
}

In C++14, you can replace if constexpr with specialization/enable_if or static_if.

like image 150
Vittorio Romeo Avatar answered Nov 29 '25 14:11

Vittorio Romeo