It doesn't seem like C++ really has a way to do this, but I'm hoping I'm wrong.
What I'd like to do is create a map (in this case to map one set of strings to another, not that the datatypes should matter really) inside a header file, so that multiple source files can then access that map directly.
Right now I just have a function defined in my header file and implemented in the source file that essentially does this exact function, but I'd prefer to use a map since I would then be able to see at one glance what the keys/values are.
The problem I'm running into with this is that populating the map requires executable code, which I can't exactly just place into a header file. Is there any good way to achieve what I'm trying to do?
There's a couple of ways to do this.
You can declare the variable in a header file, but you need to define it in a cpp file...
// FOO.H STARTS HERE
#include <map>
#include <string>
extern std::map<std::string, std::string> my_map;
// FOO.H ENDS
// FOO.CPP STARTS HERE
#include <iostream>
#include "foo.h"
std::map<std::string, std::string> my_map = {
{ "Cat", "Feline" },
{ "Dog", "Canine" },
{ "Fish", "Fish" }
};
int main (void) {
for (auto i = my_map.begin(); i != my_map.end(); ++i) {
std::cout << "A " << i->first << " is a " << i->second << std::endl;
}
return 0;
}
// FOO.CPP ENDS HERE
Alternatively, you can just keep the map in a header as long as it's const. This has the downside that it obviously only works if you don't need to change the map.
// FOO.H STARTS HERE
#include <map>
#include <string>
const std::map<std::string, std::string> my_map = {
{ "Cat", "Feline" },
{ "Dog", "Canine" },
{ "Fish", "Fish" }
};
// FOO.H ENDS HERE
// FOO.CPP STARTS HERE
#include <iostream>
#include "foo.h"
int main (void) {
for (auto i = my_map.begin(); i != my_map.end(); ++i) {
std::cout << "A " << i->first << " is a " << i->second << std::endl;
}
return 0;
}
// FOO.CPP ENDS HERE
Both of these examples assume C++11, for the use of the nice and pretty map = { }
initializer.
I took this as a challenge -- is there a header-only solution using C++03 syntax?
The answer is "yes":
// GlobalMap.hpp
#include <map>
typedef std::map<std::string, std::string> GMap;
inline
GMap & globalMap()
{
static GMap theMap;
static bool firstTime = true;
if(firstTime)
{
firstTime = false;
theMap["Cat"] = "Feline";
theMap["Dog"] = "Canine";
theMap["Guppy"] = "Fish";
}
return theMap;
}
To test this:
#include <iostream>
#include "GlobalMap.hpp"
int main()
{
for(
GMap::const_iterator it = globalMap().begin();
it != globalMap().end();
++it)
{
std::cout << '[' << it->first << "]=" << it->second << std::endl;
}
return 0;
}
Produces this output:
[Cat]=Feline
[Dog]=Canine
[Guppy]=Fish
Note I'm not recommending this solution. Just showing it as an interesting possibility.
You can use an initializer list in C++ 11: http://en.cppreference.com/w/cpp/language/list_initialization
But this doesn't solve the problem. You don't want to initialize it in a header file, you will most likely get linker errors (multiple symbol definition).
You can: 1. Use the extern keyword and initialize it in a cpp file as global variable. 2. You can make it a static variable inside a class (but still initialize it in a cpp file).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With