Я использую пару типов:
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
?
Вы не можете легко добавить свой собственный конструктор в 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, "")); }
make_nomnom
также будет хорошим именем, но я make_nomnom
более короткую версию. Но если у вашего Nomnom
действительно есть несколько инвариантов, а не просто пара, вы действительно хотите рассмотреть возможность использования класса.
ОРИГИНАЛЬНЫЙ ВОПРОС
Есть ли способ сделать это, не ограничивая вместо этого определение класса для 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
сама по себе не имеет смысла ИМХО.
ClassNoms
.
make_pair
как показано здесь.
Если вы используете С++ 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;
}
using
. Сначала не было никакой причины, но когда я попробовал это, я понял, что есть - есть набор функций, которые работают со всеми видами типов, включая обе pair<T1,T2>
и T
, поэтому, если у меня есть T
который наследует из пары я получаю неоднозначную ошибку разрешения
pair
/ tuple
.
ClassNoms(Nomnom oneIn)
иClassNoms(int key)
.int
вы можете применить, не так ли? В этом случае вы могли бы легко выйти, используя конструктор по умолчаниюClassNoms() : one(std::make_pair(-1,"")
. Или я просто пропустил то, что вы просите?