MrBZapp
MrBZapp

Reputation: 109

compile error tuple of maps getting elements by map type

I have a std::tuple of std::map containers that is defined by a variadic template like so:

template <typename KeyType, typename... ValueTypes>
class TupleMaps
{
public:
    template<typename T>
    using MapType = std::map<KeyType, T>;

    std::tuple<MapType<ValueTypes>...> member_tuple;
}

I want to get the appropriate map from the tuple by its value type and I thought I could implement a member function such as:

MapType<ValueType>& getMap() { std::get<MapType<ValueType>>(member_tuple); }

but was stopped when attempting to put together something like

TupleMaps<int, float, std::string> maps;
if (maps.getMap<float>().size() !=0) { ... };

by the compiler error "no matching function for call to get()".

What is the appropriate way to extract the correct element from a tuple by type in this case?

Upvotes: 2

Views: 181

Answers (2)

max66
max66

Reputation: 66200

As explained by NathanOlivier, get<type>(tupleValue) is a C++14 feature.

If you use a C++11 compiler, a solution can be to write a type traits to select the index of a type in a list.

By example

template <typename T, typename T0, typename ... Ts>
struct getI 
 { static constexpr std::size_t value { 1U + getI<T, Ts...>::value }; };

template <typename T, typename ... Ts>
struct getI<T, T, Ts...>
 { static constexpr std::size_t value { 0U }; };

So you can write your getMap<type>() methods as follows

   template <typename T>
   MapType<T> & getMap ()
    { return std::get<getI<T, ValueTypes...>::value>(member_tuple); }

   template <typename T>
   MapType<T> const & getMap () const
    { return std::get<getI<T, ValueTypes...>::value>(member_tuple); }

The following is a full working example

#include <map>
#include <tuple>
#include <iostream>

template <typename T, typename T0, typename ... Ts>
struct getI 
 { static constexpr std::size_t value { 1U + getI<T, Ts...>::value }; };

template <typename T, typename ... Ts>
struct getI<T, T, Ts...>
 { static constexpr std::size_t value { 0U }; };

template <typename KeyType, typename ... ValueTypes>
struct TupleMaps
 {
   template<typename T>
   using MapType = std::map<KeyType, T>;

   std::tuple<MapType<ValueTypes>...> member_tuple;

   template <typename T>
   MapType<T> & getMap ()
    { return std::get<getI<T, ValueTypes...>::value>(member_tuple); }

   template <typename T>
   MapType<T> const & getMap () const
    { return std::get<getI<T, ValueTypes...>::value>(member_tuple); }
 };

int main ()
 {
   TupleMaps<int, float, std::string> maps;

   std::cout << maps.getMap<float>().size() << std::endl; // print 0

   maps.getMap<float>()[3] = 7.5;

   std::cout << maps.getMap<float>().size() << std::endl; // print 1
 }

Upvotes: 2

NathanOliver
NathanOliver

Reputation: 180630

std::get<type> was added to C++ in C++14. In C++11 you could only use std::get<index>.

You will either have to compile with C++14 enabled or write your own version of get if you have to use C++11

Upvotes: 2

Related Questions