Как сделать псевдонимы функции-члена или переменной определенного класса (например, контейнера 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, но это все еще не кажется умным методом. Я просто хочу сделать псевдонимы.

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

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


person Cigany    schedule 06.03.2014    source источник


Ответы (3)


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

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

С С++ 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;
person CygnusX1    schedule 06.03.2014
comment
Такой простой способ! Но, таким образом, я должен написать заклинатель (string -> CommMapEntry ), чтобы использовать set::find() (кажется странным приведением?). Но это все равно было бы намного эффективнее, чем переписывать ctors с помощью std::map. Большое спасибо! - person Cigany; 06.03.2014

Как насчет некоторых определений типов и функций доступа?

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); 
    // ...
}

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

person Kerrek SB    schedule 06.03.2014
comment
Хотя это и не псевдоним (мне нравится стиль вызова с . или -›), но все же это экономичный способ. Большое спасибо. - person Cigany; 06.03.2014

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

person Cigany    schedule 11.03.2014