Как сделать псевдонимы функции-члена или переменной определенного класса (например, контейнер STL)

При использовании std :: pair или std :: map нам нужно использовать «first» или «second» для доступа к данным. Но имя двух переменных не имеет четкого значения того, что они на самом деле хранят для других сотрудников, которые не написали этот код. Так что, если мы можем сделать псевдонимы для «первого» или «второго», это значительно улучшит читабельность.

Например, следующий код

static const std::map<std::string, std::pair<std::string, PFConvert>> COMM_MAP =
{  // keyword->         (caption,                   function)
{std::string("1"), {std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}},
{std::string("2"), {std::string("Utf16LE to Utf8"), &FileConvert_Utf16LEToUtf8}},
{std::string("3"), {std::string("Utf8 to Big5"), &FileConvert_Utf8ToBig5}}
};

auto iterToExe = COMM_MAP.find(strTransType);
iterToExe->second.second();

iterToExe->second.second(); имеет действительно плохую читаемость.

Поэтому я пытаюсь использовать наследование, чтобы дать псевдонимы следующим образом

template<typename PFComm>
class CCommContent : public std::pair<std::string, PFComm>
{
public:
std::string &strCaption = std::pair<std::string, PFComm>::first;
PFComm &pfComm = std::pair<std::string, PFComm>::second;
};

template<typename PFComm>
class CCommPair : public std::pair<std::string, CCommContent<PFComm>>
{
public:
std::string &strPattern = std::pair<std::string, CCommContent<PFComm>>::first;
CCommContent<PFComm> commContent = std::pair<std::string,CCommContent<PFComm>>::second;
};

template<typename PFComm>
class CCommMap : public std::map<std::string, CCommContent<PFComm>, std::less<std::string>, std::allocator<CCommPair<PFComm>>>
{};

Но это приводит к другой проблеме: я должен объявить все ctors, хотя я мог бы вызывать базовые ctors, но это все еще не кажется разумным методом. Я просто хочу сделать псевдонимы.

Простой способ — использовать макрос …… но он обходит проверку типов. при использовании вложенной структуры при отладке это может быть кошмаром.

Любые советы или обсуждения будут оценены.

2

Решение

Почему бы просто не использовать свой собственный struct с вашими именами элементов?

struct MyPair {
std::string strCaption;
PFComm pfComm;
};

С C ++ 11 вы можете легко создавать новые объекты:

MyPair{std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}}

И если вы определите свой собственный operator<, вы можете иметь std::set работать как карта:

bool operator<(const MyPair& a, const MyPair& b) {
return a.strCaption < b.strCaption;
}

typedef std::set<MyPair> MyPairMap;

Естественно, вы можете вкладывать свои пользовательские структуры в более сложные вложенные пары, хотя в вашем случае вы можете вместо этого рассмотреть плоский триплет:

struct CommMapEntry {
std::string number;
std::string caption;
PFComm pfComm;
};
bool operator<(const MyPair& a, const MyPair& b) {
return a.number<b.number;
}
static const std::set<CommMapEntry> COMM_MAP;
2

Другие решения

Как насчет typedefs и функций доступа?

using CommEntry = std::pair<std::string, PFConvert>;

std::string const & getCaption(CommEntry const & e) { return e.first; }
PFConvert const & getFunction(CommEntry const & e) { return e.second; }

Теперь вы можете сказать:

auto it =  COMM_MAP.find(strTransType);
if (it != COMM_MAP.end())
{
auto & c = getCaption(it->second);
auto & l = getLabel(it->second);
// ...
}

Если вы позже измените детали типа, вы просто адаптируете функции доступа.

2

ну в с ++ 11 мы можем using base::base в производном классе использовать базовые ctors. Но обратите внимание, что vs2013 НЕ соответствует этому. g ++ 4.8 do.

1