Cigany
Cigany

Reputation: 178

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.

Upvotes: 2

Views: 1211

Answers (3)

Cigany
Cigany

Reputation: 178

well, in c++11, we can using base::base in a derive class to use the base ctors. But note that vs2013 DO NOT compliant this. g++4.8 do.

Upvotes: 1

CygnusX1
CygnusX1

Reputation: 21808

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;

Upvotes: 2

Kerrek SB
Kerrek SB

Reputation: 477368

How about some typedefs and accessor functions?

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

Now you can say:

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

If you later change the details of the type, you just have adapt the accessor functions.

Upvotes: 2

Related Questions