Search code examples
c++inheritancestlmemberaliases

How to make aliases of member function or variable of specific class(like an STL container)


When using a std::pair or std::map, we need to use "first" or "second" to access data. But the two variable name do not have clear meanings of what it really store for other co-workers that did not write this code. So if we can make aliases for "first" or "second", it would enhance much readability.

For example, the following code

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();

The iterToExe->second.second(); has a truly bad readability.

So I try to use inherit to give aliases as following

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>>>
{};

But this comes to an another issue: I have to declare all the ctors, though i could call the base ctors, but it still not seems to be a smart method. I Just want to make aliases.

A simple way is to use macro ...... but it bypass the type checking. when using a nested structure, it may be a nightmare when debug.

Any advice or discussion would be appreciated.


Solution

  • Why not simply use your own struct with your own element names?

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

    With C++11 you can easily create new objects of it:

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

    And if you define your own operator<, you can have std::set work as a map:

    bool operator<(const MyPair& a, const MyPair& b) {
        return a.strCaption < b.strCaption;
    }
    
    typedef std::set<MyPair> MyPairMap;
    

    Naturally, you can nest your custom structs to form more complex nested pairs, although in your case you might want to consider a flat triplet instead:

    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;