Как обеспечить значение по умолчанию для первой пары?

0

Я использую пару типов:

typedef std::pair<int, std::string> Nomnom;

Пример использования:

void DoIt(const Nomnom &toNom) { 
    ...
}
void DoItAgain(const Nomnom &toNomAgain) { 
    ...
}

В моем случае имеет смысл предложить значение по умолчанию для пары, если оно не указано. То есть, я хочу иметь возможность сделать это:

DoIt("Thisisit");
DoItAgain("Thisisit");

и это будет эквивалентно этому:

DoIt(NomNom(0, "Thisisit"));
DoItAgain(NomNom(0, "Thisisit"));

Я хочу сделать это, не определяя два варианта каждый раз, когда используется Nomnom.

Есть ли способ сделать это, не ограничивая определение класса для Nomnom вместо typedef, предоставляя конструктор с одним аргументом, а затем предоставляя конструкторы с нулевым аргументом и двумя аргументами, которые вызывают конструкторы std::pair?

  • 0
    Да, это называется перегрузкой. Вы можете иметь как ClassNoms(Nomnom oneIn) и ClassNoms(int key) .
  • 0
    Зависит от того, какой разумный дефолт для int вы можете применить, не так ли? В этом случае вы могли бы легко выйти, используя конструктор по умолчанию ClassNoms() : one(std::make_pair(-1,"") . Или я просто пропустил то, что вы просите?
Показать ещё 2 комментария
Теги:
constructor
default
std-pair

3 ответа

2
Лучший ответ

Вы не можете легко добавить свой собственный конструктор в std::pair (наследование от него на самом деле не является вариантом).

Но вы можете создать небольшую функцию для ее создания и перегрузить ее соответственно:

Nomnom nomnom(const std::string& s) { return Nomnom(-1, s); }
Nomnom nomnom(int i) { return Nomnom(i, ""); }

Вы также можете перегрузить DoIt и DoIt и DoItAgain на общую реализацию.

void DoIt(const Nomnom& n) { /* ... */ }
void DoIt(int i) { DoIt(Nomnom(i, "")); }
  • 0
    О, хе, это имеет смысл. Я думал об этом, решил не по какой-то причине, потому что я хотел конструктор, но для кода, который его использует, он выглядит примерно так же
  • 2
    Клаудия, make_nomnom также будет хорошим именем, но я make_nomnom более короткую версию. Но если у вашего Nomnom действительно есть несколько инвариантов, а не просто пара, вы действительно хотите рассмотреть возможность использования класса.
2

ОРИГИНАЛЬНЫЙ ВОПРОС

Есть ли способ сделать это, не ограничивая вместо этого определение класса для Nomnom, предоставляя конструктор с одним аргументом, а затем предоставляя конструкторы с нулевым аргументом и двумя аргументами, которые вызывают конструкторы std :: pair?

У вас может быть больше перегрузок конструктора, поскольку

ClassNoms() : one(std::make_pair(-1,"") {}
ClassNoms(int id) : one(std::make_pair(id,"") {}
ClassNoms(const std::string& name) : one(std::make_pair(-1,name) {}
ClassNoms(int id, const std::string& name) : one(std::make_pair(id,name) {}

ОБНОВИТЬ:

Есть ли способ сделать это, не Nomnom определение класса для Nomnom вместо typedef, предоставляя конструктор с одним аргументом, а затем предоставляя конструкторы с нулевым аргументом и двумя аргументами, которые вызывают конструкторы std::pair?

typedef std::pair<int, std::string> Nomnom;

Вы не можете предоставить конструктор по умолчанию для своего typedef 'd NomNom, потому что std::pair<> не предоставляет его. Для этого вам нужно либо наследовать класс NomNom из std::pair<>, либо IMHO лучше предоставить оболочку для него и использовать его:

template<typename First,typename Second>
struct DefaultValuedPair {
     std::pair<First,Second> value;
     First& first;
     Second& second;
     DefaultValuedPair
        ( const First& first = First()
        , const Second& second = Second()
        ) 
     : value(std::make_pair(first,second))
     , first(value.first)
     , second(value.second) {}
     DefaultValuedPair(const std::pair<First,Second>& rhs) 
     : value(rhs)
     , first(value.first)
     , second(value.second) {}
     // Add more implicit type conversions for std::pair<First,Second>
     // as necessary ...
};

И имеют

typedef DefaultValuedPair<int, std::string> Nomnom;

У вас может быть функция, которая действует как конструктор, но ее нельзя назвать и назвать чистым эквивалентом для типа NomNom (объявленного), и это не даст никакого преимущества по сравнению с использованием std::make_pair().

Предлагаемое решение обертки может оказать огромное влияние на соображения рефакторинга уже существующего кода, который использует NomNom, и должен работать с ним без проблем. Как уже упоминалось, просто замена/маскировка std::make_pair сама по себе не имеет смысла ИМХО.

  • 0
    Я проверяю мои изменения, это не то, что я спрашивал. Притворись, я никогда не упоминал ClassNoms .
  • 0
    @Claudiu Это та же идея. Просто используйте make_pair как показано здесь.
Показать ещё 6 комментариев
1

Если вы используете С++ 11, вы можете просто наследовать конструкторы из пары с using. Я думаю, что это самое чистое решение вашей проблемы.

Есть ли причина (к тому же, не желая повторно реализовывать конструкторы std::pair), вы не хотите наследовать от std :: pair?

#include <utility>
#include <string>
#include <iostream>

/**
 * Nomnom is just a std::pair with a customized constructor.
 */
class Nomnom : public std::pair <int, std::string> {
  typedef std::pair<int, std::string> parent_type; // For convenience

  public:
  using parent_type::parent_type; // Inherit Pair constructors
  Nomnom (std::string S) : parent_type(0, S) {} // And add our own
  Nomnom (char const * S) : parent_type(0, S) {} // Handle C strings...
};

/**
 * Show that we can just use Nomnom as a std::pair...
 */
template <class FIRST, class SECOND> 
std::ostream & operator<< (std::ostream & out, std::pair <FIRST, SECOND> const & print_me) {
  return out << print_me.first << ", " << print_me.second << '\n';
}

/**
 * Use this to test initizlization while passing to a method
 */
void foo (Nomnom const & print_me) {
  std::cout << print_me;
}

int main (void) {
  std::cout << Nomnom("Hello!");
  std::cout << Nomnom(5, "World!");
  foo ("Mouse!");

  return 0;
}
  • 0
    О, аккуратно, не знал об using . Сначала не было никакой причины, но когда я попробовал это, я понял, что есть - есть набор функций, которые работают со всеми видами типов, включая обе pair<T1,T2> и T , поэтому, если у меня есть T который наследует из пары я получаю неоднозначную ошибку разрешения
  • 0
    Позвольте мне добавить очевидное: наследование от типа, у которого нет виртуального деструктора, является плохой идеей. Это касается почти всех стандартных типов библиотек. Кроме того, это нарушает все виды специализаций шаблонов, которые библиотека может предоставить для интерфейса « pair / tuple .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню