Bryce
Bryce

Reputation: 37

unordered_map initialization with #include

std::unordered_map<std::string, std::string> mimeMap = {
    #define STR_PAIR(K,V) std::pair<std::string, std::string>(K,V)
    #include "MimeTypes.inc"
};

File MimeTypes.inc is like:

STR_PAIR("3dm", "x-world/x-3dmf"),
STR_PAIR("3dmf", "x-world/x-3dmf"),
STR_PAIR("a", "application/octet-stream"),
STR_PAIR("aab", "application/x-authorware-bin"),
STR_PAIR("aam", "application/x-authorware-map"),
STR_PAIR("aas", "application/x-authorware-seg"),
STR_PAIR("abc", "text/vnd.abc"),
STR_PAIR("acgi", "text/html"),
STR_PAIR("afl", "video/animaflex"),
STR_PAIR("ai", "application/postscript"),
STR_PAIR("aif", "audio/aiff"),

I am very confused. How does this code initialise an unordered_map?

Upvotes: 2

Views: 233

Answers (2)

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

From the reference documentation you have the option to use a std::initializer_list constructor (5):

map( std::initializer_list<value_type> init,
     const Compare& comp = Compare(),
     const Allocator& alloc = Allocator() );

the macro builds one from the std::pairs and the #include directive replaces the text within the {} braces. Finally this evaluates to:

std::unordered_map<std::string, std::string> mimeMap = {
    #define STR_PAIR(K,V) std::pair<std::string, std::string>(K,V)
    std::pair<std::string, std::string>("3dm", "x-world/x-3dmf"),
    std::pair<std::string, std::string>("3dmf", "x-world/x-3dmf"),
    std::pair<std::string, std::string>("a", "application/octet-stream"),
    std::pair<std::string, std::string>("aab", "application/x-authorware-bin"),
    std::pair<std::string, std::string>("aam", "application/x-authorware-map"),
    std::pair<std::string, std::string>("aas", "a");
    std::pair<std::string, std::string>(pplication/x-authorware-seg"),
    std::pair<std::string, std::string>("abc", "text/vnd.abc"),
    std::pair<std::string, std::string>("acgi", "text/html"),
    std::pair<std::string, std::string>("afl", "video/animaflex"),
    std::pair<std::string, std::string>("ai", "application/postscript"),
    std::pair<std::string, std::string>("aif", "audio/aiff"),    
};

Upvotes: 1

krzaq
krzaq

Reputation: 16431

#include does textual copy-paste. It's almost as if you had written the following directly:

std::unordered_map<std::string, std::string> mimeMap = {
    #define STR_PAIR(K,V) std::pair<std::string, std::string>(K,V)
    STR_PAIR("3dm", "x-world/x-3dmf"),
    // ...
    STR_PAIR("aif", "audio/aiff"),
}; 

Now, STR_PAIR is a preprocessor macro that replaces its arguments with std::pair<std::string, std::string>(K,V), K and V being the parameters of the macro. For example, the above snippet is no different than:

std::unordered_map<std::string, std::string> mimeMap = {
    std::pair<std::string, std::string>("3dm", "x-world/x-3dmf"),
    // ...
    std::pair<std::string, std::string>("aif", "audio/aiff"),
}; 

If you're using gcc or clang, you can use -E command line option to get preprocessed output and see for yourself. Be aware that it'll be quite big, though.

Finally, such pair is used to copy-initialize elements of mimeMap.

This code is also buggy, because map's value_type is pair<const Key, Value>, so STR_PAIR should actually create std::pair<std::string const, std::string>

Upvotes: 10

Related Questions