Подтвердить что ты не робот

Как остановить автоматическое преобразование из int в float и наоборот в std:: map

Я написал небольшую программу использования std:: map здесь следующим образом.

int main()
{
  map<int,float>m1;
  m1.insert(pair<int,float>(10,15.0));   //step-1
  m1.insert(pair<float,int>(12.0,13));   //step-2
  cout<<"map size="<<m1.size()<<endl;    //step -3

Я создал карту с типом типа int в качестве ключа и типа float в качестве пары значений (ключ-значение) для карты m1

step-1 Создал нормальную пару с int-float и вставил в карту.

step-2 Создал пару cross float-int и вставлен в карту. Теперь я знаю, что неявное преобразование делает эту пару вставленной в карту.

Здесь я просто не хочу, чтобы неявное преобразование выполнялось, и должна быть указана ошибка компилятора.

Какие изменения я должен сделать в этой программе/карте, чтобы сделать флаг comipiler ошибкой, когда мы пытаемся выполнить операцию типа 2?

Спасибо заранее.

4b9b3361

Ответ 1

Вот предложение:

template <typename K, typename V, typename W>
void map_insert(map<K,V>& m, K k, W w) {
  V v = w;
  m.insert(pair<K,V>(k,v));
}

int main() {
  map<int,float>m1;
  map_insert(m1, 10, 15.0);
  map_insert(m1, 12.0, 13);  // compiler complains here
  cout<<"map size="<<m1.size()<<endl;

Третий параметр шаблона немного неудобен, но необходимо, чтобы кастинг от double до float.

Ответ 2

Это невозможно (и даже если это возможно, тогда это будет основной хак, который вы не должны использовать).

insert принимает аргумент value_type, который является pair<int const,float>. Итак, когда вы пытаетесь вставить pair<float, int>, компилятор ищет преобразование, то есть: конструктор pair<int const, float>, который принимает аргумент pair<float, int>, который просто существует. Фактически, я попытался придумать частичную специализацию для этого члена шаблона (который позволяет преобразовать), который тогда вы могли бы сбой по оставшемуся параметру шаблона, но я этого не сделал; это кажется невозможным. Во всяком случае, это был бы очень грязный хак, который вы просто не должны делать, чтобы избежать опечатки. В другом месте вам может понадобиться это преобразование, и в любом случае нет никакого определения в пространстве имен std.

Итак, что такое решение "Как я могу избежать такого рода опечаток?"

Вот что я обычно делаю:

1) Все мои карты имеют typedef для их типа.
2) Затем я использую ::value_type::iterator и т.д.) Только для этого типа.

Это не только более надежное, но и более гибкое: вы можете позже изменить тип контейнера и, скорее всего, код будет работать.

Итак, ваш код будет выглядеть следующим образом:

int main()
{
  typedef std::map<int,float> m_type;
  m_type m1;

  m1.insert(m_type::value_type(10,15.0));   // allowed
  m1.insert(m_type::value_type(12.0,13));   // no risk for a typo.

Альтернативным решением будет обернуть ваш float в пользовательский класс. В любом случае, это не так уж плохо, потому что (опять) причины гибкости. Очень редко приходится писать код с помощью std::map<int, builtin-type>, чтобы понять, что вам нужно хранить больше данных, и, поверьте, это происходит очень часто. Вы могли бы начать с класса с самого начала.

Ответ 3

Может быть, есть более простой способ, но это то, что произошло со мной:

#include <iostream>
#include <map>

template<typename Key, typename Value>
struct typesafe_pair
{
    const Key& key;
    const Value& value;
    explicit typesafe_pair(const Key& key, const Value& value): key(key), value(value) {}

    operator typename std::map<Key, Value>::value_type() { return typename std::map<Key, Value>::value_type(key, value); }
};

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

  m1.insert(std::pair<int,float>(10,15.0));   // allowed
  m1.insert(std::pair<float,int>(12.0,13));   // allowed!!

  m1.insert(typesafe_pair<int,float>(10, 15.0)); // allowed
  m1.insert(typesafe_pair<float, int>(12.0, 13)); // compiler error

  std::cout << "map size=" << m1.size() << std::endl;    //step -3
}

РЕДАКТИРОВАТЬ: 1 Кто-то может предоставить лучшее (более эффективное) решение, включающее ссылки на rvalue и совершенную магию переадресации, которую я пока не совсем понимаю.

EDIT 2: Я думаю, что Carlo Wood имеет лучшее решение IMHO.