Shloim February 2016

C++11: Implementing a Selector between std::array and std::unordered_map according to item count

I'm trying to create a mapping class that would automatically select the proper implementation according to the possible value range. If the value range is up to 256, use an std::array, otherwise, use std::unordered_map.

template<typename KeyType, typename ValType>
class MapImpl : public std::unordered_map<KeyType,ValType>
{
  void foo() { std::cout << "Map foo" << std::endl; }
};

template<typename ValType, std::size_t Size>
class ArrImpl : public std::array<ValType,Size>
{
public:
  void foo() { std::cout << "Arr foo" << std::endl; }
};

template<typename KeyType, typename ValType,
         KeyType min_value = boost::integer_traits<KeyType>::const_min,
         KeyType max_value = boost::integer_traits<KeyType>::const_max>
class MappingSelector
{
public:
  void bar() { map.foo(); }
private:
  typedef std::conditional<(max_value-min_value < 256),
                           ArrImpl<ValType,max_value-min_value+1>,
                           MapImpl<KeyType,ValType>
                          > MappingType;
  MappingType map;
};

So far so good(?) I then instantiate it with:

MappingSelector<unsigned char, double> ms;
ms.bar();

However, the compiler doesn't seem to like this and tells me that my MappingType has no member named foo.

Answers


Jack February 2016

std::conditional doesn't define directly the resulting type, but it defines a struct which has a typedef type which is the corresponding type.

This means that you must qualify the specific type, so your typedef should be

typedef std::conditional<(max_value-min_value < 256),
ArrImpl<ValType,max_value-min_value+1>,
MapImpl<KeyType,ValType>
> MappingType;
typename MappingType::type map;
    ^ requires typename for unambiguation
                       ^ ::type is the real typedef

Or you can typedef MappingType directly by qualifying it with ::type, same result. Actually, since you are working with C++11 you can also use using, eg:

using MappingType = typename std::conditional<(max_value-min_value < 256),
ArrImpl<ValType,max_value-min_value+1>,
MapImpl<KeyType,ValType>
>::type;

MappingType map;


Ami Tavory February 2016

The problem might be with

typedef std::conditional<(max_value-min_value < 256),
                       ArrImpl<ValType,max_value-min_value+1>,
                       MapImpl<KeyType,ValType>
                      > MappingType;

Where you might have meant

typedef typename std::conditional<(max_value-min_value < 256),
                       ArrImpl<ValType,max_value-min_value+1>,
                       MapImpl<KeyType,ValType>
                      >::type MappingType;

You didn't actually typedef here one of the types you meant (IIUC); rather. you typedefed the "if statement" of the type.


See here examples of how to use this construct.


Brian February 2016

std::conditional is a trait class that exposes the chosen type as ::type. So you need to do this:

  typedef typename std::conditional<...>::type MappingType;

If you have C++14, you can simplify this by using the alias template instead:

  typedef std::conditional_t<...> MappingType;

Post Status

Asked in February 2016
Viewed 2,831 times
Voted 6
Answered 3 times

Search




Leave an answer