Related
I am looking for naming conventions for typedef of lengthy collections definitions. We have some c++ code which used auto to get away with style murder, but we need to make this code compiling on a non c++11 compiler. We are looking to establish a convention for typedef of collections, which can become quite lengthy
For instance
typedef std::map<enum MyFirstEnum,enum MySecondEnum> map_enum2_by_enum1_t
typedef map_enum2_by_enum1_t::value_type vtype_map_enum2_by_enum1_t
typedef map_enum2_by_enum1_t::iterator map_iterator_enum2_by_enum1_t
There are so many nuances (iterator before t than at beginning, using type rather than t, ditching the prefix map, etc...) that half of the time you select one nuance, half of the time you select the other.
At the end no typedef look like the other.
typedef std::map<enum MyFirstEnum,enum MySecondEnum> map_enum2_by_enum1_t;
If there's no "big picture" name that better describes the mapping, then I'd suggest Enum2_By_Enum1 or Enum1_To_Enum2: both imply an associative container without the map bit, which is a bit too Hungarian for my taste, with all the same flaws (e.g. if you move to say unordered_map will you change it - if you remember - or leave it being misleading?).
typedef map_enum2_by_enum1_t::value_type vtype_map_enum2_by_enum1_t;
I can't imagine this being useful... I'd typically only typedef a map's value_type inside a template when the concrete value type is unknown (e.g. the map or value type is one of the template parameters) and the map has no special or exclusive significance such that its value_type can reasonably be typedefed as the template's value_type, and in that scenario the map will necessarily have some other higher-level name reflecting its role in the template instantiation.
In conclusion, I'd omit this if at all possible and use enum2/MyFirstEnum directly.
typedef map_enum2_by_enum1_t::iterator map_iterator_enum2_by_enum1_t;
There's no reason for this unless the typedef identifier is significantly shorter than what it aliases. Just use <mapname>::iterator.
If you think you've got specific examples of code that's improved by having these last two typedefs, please share it.
All this is obviously subjective. That said, I tend to use a namespace to separate/isolate types, and keep names small/short:
enum foo_result;
enum bar_state;
enum baz_values;
namespace mappings { // namespace name tells you what's inside, so there is
// no need to call names inside with "map_" prefix
// "associate foo_result to bar_state"
typedef std::map<foo_result,bar_state> foo_result2bar_state;
// "associate foo_result to baz_values"
typedef std::map<foo_result,baz_values> foo_result2baz_values;
// I would not define these here:
// typedef foo_result2bar_state::value_type
// foo_result2bar_state_value_type;
}
Client code then becomes self-descriptive:
void f(mappings::foo_result2bar_state& m) // foo_result2bar_state is a "mapping" of types
{
// I prefer to have this alias in client code (i.e. where I use it)
typedef mappings::foo_result2bar_state::iterator itr;
itr begin = m.begin();
// ...
}
There are all sorts of ways.
Usually, I would aim to avoid the problem from the beginning, by deriving the typenames from the top level design rather than from types used to implement it. From a top level perspective, there is usually some concept that a type represents, and that concept is usually a suitable name - right from early design. Retrofitting things like type names onto existing sloppy code is really a bad idea.
But, given that this is your starting point, I suggest not being too lavish in adorning the names and do something like this.
namespace <libname>_Type
{
typedef std::map<FirstEnum, SecondEnum> map_first_second;
typedef map_first_second::value_type map_first_second_value;
typedef map_first_second::iterator map_first_second_iterator;
typedef map_first_second::const_iterator map_first_second_const_iterator;
}
or (if your library has its own namespace)
namespace <libname>
{
namespace Type
{
typedef std::map<FirstEnum, SecondEnum> map_first_second;
typedef map_first_second::value_type map_first_second_value;
typedef map_first_second::iterator map_first_second_iterator;
typedef map_first_second::const_iterator map_first_second_const_iterator;
}
}
Now, okay, the use of namespaces may make mean a bit more work to set up, but using the types is easier.
for (<libname>::Type::map_first_second_iterator i, end = some_map.end();
i != end;
++i)
{
do_something(i);
}
which can be simplified to avoid all the scoping with a judicious using.
If your style guidelines allow or require, it is possible to avoid use of underscore by using camel-case (e.g. instead of map_first_second_iterator use MapFirstSecondIterator. The key, for developers, is being consistent in using your naming conventions and not over-complicating it, rather than having a perfect one.
Apologies in advanced if this is the wrong site, please let me know if it is!
I've written a function that checks to see whether a key exists in a particular std::map and wondered if this is a good practise to use, and, whether or not anyone can throw any pointers on improvements.
The std::map allows for multiple data-types to be accepted for the value.
union Variants {
int asInt;
char* asStr;
Variants(int in) { asInt = in; }
Variants() { asInt = 0;}
Variants(char* in) { asStr = in; }
operator int() { return asInt; }
operator char*() { return asStr; }
};
template<typename T, typename Y>
bool in_map(T value, std::map<T, Y> &map)
{
if(map.find(value) == map.end()) {
return false;
}else{
return true;
}
}
And I can then use in main the following:
std::map<string, Variants> attributes;
attributes["value1"] = 101;
attributes["value2"] = "Hello, world";
if(in_map<std::string, Variants>("value1", attributes))
{
std::cout << "Yes, exists!";
}
Any help or advise would be greatly appreciated. Sorry if this doesn't comply to the rules or standards. Thanks!
The biggest problem I see with your function is that you're throwing away the resulting iterator.
When you're checking if a key exists in a map, most of the time you want to retrieve/use the associated value after that. Using your function in that case forces you to do a double lookup, at the cost of performance. I would just avoid the use of the function altogether, and write the tests directly, keeping the iterator around for later use in order to avoid useless lookups:
auto it = map_object.find("key");
if (it != map_object.end())
use(it->second);
else
std::cout << "not found" << std::endl;
Of course if you're just checking whether a key exists and don't care for the associated value then your function is fine (taking into account what others told you in the comments) but I think its use cases are quite limited and not really worth the extra function. You could just do:
if (map_object.find("key") != map_object.end())
std::cout << "found, but I don't care about the value" << std::endl;
ny pointers on improvements.
sure.
template<typename T, typename Y>
bool in_map(T value, const std::map<T, Y> &map)
{
return map.find(value) != map.end();
}
And I'd place map as 1st parameter (just a preference). Also, because the whole thing fits into single line, you might not even need this function.
You're also throwing away returned iterator, but since you aren't using it, that's not a problem.
Apart from this, does this look ok in terms of coding practise? I.e. Using Union or are there other types I can use such as struct?
Well, using char* doesn't looke like a good idea, because char* implies that you can modify data. char* also implies that this pointer is dynamically allocated and you might want to delete[] that pointer later. And you can't use destructors in unions. If the text cannot be changed, you could use const char*, otherwise you might want to use different datatype. Also see Rule of Three
Next problem - you're trying to place char* and int at the same location. That implies that at some point you're trying to convert pointer to integer. Which is a bad idea, because on 64bit platform pointer might not fit into int, and you'll get only half of it.
Also, if you're trying to store multiple different values in the same variable, you are not indicating which type is being stored anywhere. To do that you would need to enclose union into struct and add field (into struct) that indicates type of stored object. In this case, however, you'll end up reinventing the wheel. So if you're trying to store "universal" type, you might want to look at Boost.Any, Boost.Variant or QVariant. All of those require BIG external libraries, though (either boost or Qt).
Typing
if(in_map<std::string, Variants>("value1", attributes))
seems a bit excessive to me, typing all of that typename syntax makes me want to just use the map.find function instead just out of convenience. However, depending on your compiler, sometimes the template parameters can be interpreted automatically, for example, visual studio will allow this:
if(in_map(std::string("value1"), attributes))
In this case, I had to construct an std::string object to replace the char*, but I've completely removed the template definition from the call, the compiler still figures out what T and Y are based on the parameters given.
However, my recommended advice would be to use #define to define your "function". While it is not really a function, since #define actually just replaces snippets of code directly into the source, it can make things much easier and visually appealing:
#define in_map(value,map) (map.find(value) != map.end())
Then your code to use it would just look like this:
if(in_map("value1", attributes))
You both get the optimization of not using a function call, and the visual appearance like it does in PHP.
We have a const array of structs, something like this:
static const SettingsSuT _table[] = { {5,1}, {1,2}, {1,1}, etc };
the structure has the following:
size_bytes:
num_items:
Other "meta data" members
So the "total size" is size_bytes*num_items for a single element. All of this information is in the const array, available at compile time. But, please note, the total size of _table is not related to the size of the EEPROM itself. _table does not mirror the EEPROM, it only describes the layout, usage, and other "meta data" type information we need. But, you can use this meta data to determine the amount of EEPROM we are using.
The array simply describes the data that is stored in an external EEPROM, which has a fixed/maximum size. As features are added and removed, the entries in the const array changes. We currently have a runtime check of the total size of the data to insure that it does not exceed the EEPROM size.
However, we have been changing over many of these runtime checks to static_assert style template checks, so that the build stops immediately. I'm not a template expert, so could use some help on this one.
So, the question: how to create a template to add up the size of all the elements (multiplying the values of each element, and then adding all the results) and then do a static_assert and stop the build if they exceed the magic number size of the EEPROM. I was looking at the typical recursive factorial template example as one approach, but it can not access the array, it requires a const value ( I think ).
thank you very much for any help,
Your problem is that they are constant, but they are not constant expressions when evaluated:
// f is constant, but its value not known at compile-time
int const f = rand() % 4;
What you need are true constant expressions. You can use boost::mpl to make up a mpl vector of mpl pairs, each with a pair of integral constants:
using namespace boost::mpl;
typedef vector<
pair< int_<5>, int_<1> >,
pair< int_<1>, int_<2> >,
pair< int_<1>, int_<1> >,
> numbers;
Now, you can iterate over the items of it using boost::mpl algorithms. Each int_ is exposes a static int constant value set to the value you told it. That will evaluate to a constant expression:
// get at the first element of the pair, located in the first element
// of the vector. Then get its ::value member.
int array[at<numbers, 0>::type::first::value];
And that would actually make that array contain 5 elements.
Website of boost::mpl Reference Manual: Here
If you change the values to be template parameters rather than constructor arguments or some other runtime initialized value, then they are constants that can be used for your static_asserts.
I'm not sure how this could work for an array of the structs though. You may need to declare your structs using some macro preprocessor magic so that it keeps track of your allocations for you.
BEGIN_EEPROM_STRUCT_TABLE()
STRUCT(size, num_bytes)
// etc.
END_EEPROM_STRUCT_TABLE()
This could possibly declare your table and a const that adds up all the sizes, provided they are constant at compile time (and that you write the macros appropriately, of course).
From my armchair I would be inclined to try to express the configuration data as a struct so that the size can be checked at compile time (any static assert can do this). Hard to say whether this would be a suitable approach, based on the information provided, but equally, on the same grounds I can't see any immediate reason to dismiss it.
A basic translation of the table would be something like:
struct SettingsTable
{
char a[5][1];//maybe call it "featureX_conf", or whatever...
char b[1][2];
char c[1][1];
};
(Insert suitable compiler magic to remove padding and alignment, though in practice char seems generally immune to this kind of thing on the majority of platform/compiler combinations.)
Then to get sizes one can use sizeof as appropriate. If the actual table of values is still necessary, it could be generated this way. It would be a bit ugly, but easily-enough hidden behind a macro.
Whether this would be "better" than a more template-heavy approach probably depends on the target market.
This is essentially the same answer as litb, but also shows how to add the sizes up w/o hard coding the array size. That's why it appears so complicated.
It's not clear what part you need help with. Below is how you use types to track all the meta data rather than an array in memory. This allows compile time checks with enums that you can't do with const int in structs. If you have more metadata, add additional parameters in the template for Settings and store them as enum values.
Using the Loki library: http://loki-lib.sourceforge.net/index.php?n=Main.Development. It's limited to 18 "Settings" because of how MakeTypeList is implemented.
You can use TypeAt<TList, index>::Result::size_bytes (for example) to access the meta data.
#include "loki-0.1.7\include\loki\typelist.h"
#include "loki-0.1.7\include\loki\static_check.h"
using namespace Loki;
using namespace Loki::TL;
// based on the Length<> template from loki for adding up the sizes
template <class TList> struct TotalSize;
template <> struct TotalSize<NullType>
{ enum { value = 0 }; };
template <class T, class U>
struct TotalSize< Typelist<T, U> >
{ enum { value = T::size_bytes*T::num_items + TotalSize<U>::value }; };
// struct for holding the sizes (and other meta data
// if you add extra template args and enum values)
template <size_t s, size_t n> struct Settings
{ enum { size_bytes = s, num_items = n }; };
// the table of setting structs (limited to 18)
typedef MakeTypelist< Settings<5,1>, Settings<1,2>, Settings<1,1> >
SettingsSuT;
int _tmain(int argc, _TCHAR* argv[])
{
LOKI_STATIC_CHECK(TotalSize< SettingsSuT::Result >::value == 8,is8);
// this will trigger at compile time if uncommented
//LOKI_STATIC_CHECK(TotalSize< SettingsSuT::Result >::value != 8,isnt8);
int x = TotalSize< SettingsSuT::Result >::value;
return 0;
}
I'm trying to get my head around tuples (thanks #litb), and the common suggestion for their use is for functions returning > 1 value.
This is something that I'd normally use a struct for , and I can't understand the advantages to tuples in this case - it seems an error-prone approach for the terminally lazy.
Borrowing an example, I'd use this
struct divide_result {
int quotient;
int remainder;
};
Using a tuple, you'd have
typedef boost::tuple<int, int> divide_result;
But without reading the code of the function you're calling (or the comments, if you're dumb enough to trust them) you have no idea which int is quotient and vice-versa. It seems rather like...
struct divide_result {
int results[2]; // 0 is quotient, 1 is remainder, I think
};
...which wouldn't fill me with confidence.
So, what are the advantages of tuples over structs that compensate for the ambiguity?
tuples
I think i agree with you that the issue with what position corresponds to what variable can introduce confusion. But i think there are two sides. One is the call-side and the other is the callee-side:
int remainder;
int quotient;
tie(quotient, remainder) = div(10, 3);
I think it's crystal clear what we got, but it can become confusing if you have to return more values at once. Once the caller's programmer has looked up the documentation of div, he will know what position is what, and can write effective code. As a rule of thumb, i would say not to return more than 4 values at once. For anything beyond, prefer a struct.
output parameters
Output parameters can be used too, of course:
int remainder;
int quotient;
div(10, 3, "ient, &remainder);
Now i think that illustrates how tuples are better than output parameters. We have mixed the input of div with its output, while not gaining any advantage. Worse, we leave the reader of that code in doubt on what could be the actual return value of div be. There are wonderful examples when output parameters are useful. In my opinion, you should use them only when you've got no other way, because the return value is already taken and can't be changed to either a tuple or struct. operator>> is a good example on where you use output parameters, because the return value is already reserved for the stream, so you can chain operator>> calls. If you've not to do with operators, and the context is not crystal clear, i recommend you to use pointers, to signal at the call side that the object is actually used as an output parameter, in addition to comments where appropriate.
returning a struct
The third option is to use a struct:
div_result d = div(10, 3);
I think that definitely wins the award for clearness. But note you have still to access the result within that struct, and the result is not "laid bare" on the table, as it was the case for the output parameters and the tuple used with tie.
I think a major point these days is to make everything as generic as possible. So, say you have got a function that can print out tuples. You can just do
cout << div(10, 3);
And have your result displayed. I think that tuples, on the other side, clearly win for their versatile nature. Doing that with div_result, you need to overload operator<<, or need to output each member separately.
Another option is to use a Boost Fusion map (code untested):
struct quotient;
struct remainder;
using boost::fusion::map;
using boost::fusion::pair;
typedef map<
pair< quotient, int >,
pair< remainder, int >
> div_result;
You can access the results relatively intuitively:
using boost::fusion::at_key;
res = div(x, y);
int q = at_key<quotient>(res);
int r = at_key<remainder>(res);
There are other advantages too, such as the ability to iterate over the fields of the map, etc etc. See the doco for more information.
With tuples, you can use tie, which is sometimes quite useful: std::tr1::tie (quotient, remainder) = do_division ();. This is not so easy with structs. Second, when using template code, it's sometimes easier to rely on pairs than to add yet another typedef for the struct type.
And if the types are different, then a pair/tuple is really no worse than a struct. Think for example pair<int, bool> readFromFile(), where the int is the number of bytes read and bool is whether the eof has been hit. Adding a struct in this case seems like overkill for me, especially as there is no ambiguity here.
Tuples are very useful in languages such as ML or Haskell.
In C++, their syntax makes them less elegant, but can be useful in the following situations:
you have a function that must return more than one argument, but the result is "local" to the caller and the callee; you don't want to define a structure just for this
you can use the tie function to do a very limited form of pattern matching "a la ML", which is more elegant than using a structure for the same purpose.
they come with predefined < operators, which can be a time saver.
I tend to use tuples in conjunction with typedefs to at least partially alleviate the 'nameless tuple' problem. For instance if I had a grid structure then:
//row is element 0 column is element 1
typedef boost::tuple<int,int> grid_index;
Then I use the named type as :
grid_index find(const grid& g, int value);
This is a somewhat contrived example but I think most of the time it hits a happy medium between readability, explicitness, and ease of use.
Or in your example:
//quotient is element 0 remainder is element 1
typedef boost:tuple<int,int> div_result;
div_result div(int dividend,int divisor);
One feature of tuples that you don't have with structs is in their initialization. Consider something like the following:
struct A
{
int a;
int b;
};
Unless you write a make_tuple equivalent or constructor then to use this structure as an input parameter you first have to create a temporary object:
void foo (A const & a)
{
// ...
}
void bar ()
{
A dummy = { 1, 2 };
foo (dummy);
}
Not too bad, however, take the case where maintenance adds a new member to our struct for whatever reason:
struct A
{
int a;
int b;
int c;
};
The rules of aggregate initialization actually mean that our code will continue to compile without change. We therefore have to search for all usages of this struct and updating them, without any help from the compiler.
Contrast this with a tuple:
typedef boost::tuple<int, int, int> Tuple;
enum {
A
, B
, C
};
void foo (Tuple const & p) {
}
void bar ()
{
foo (boost::make_tuple (1, 2)); // Compile error
}
The compiler cannot initailize "Tuple" with the result of make_tuple, and so generates the error that allows you to specify the correct values for the third parameter.
Finally, the other advantage of tuples is that they allow you to write code which iterates over each value. This is simply not possible using a struct.
void incrementValues (boost::tuples::null_type) {}
template <typename Tuple_>
void incrementValues (Tuple_ & tuple) {
// ...
++tuple.get_head ();
incrementValues (tuple.get_tail ());
}
Prevents your code being littered with many struct definitions. It's easier for the person writing the code, and for other using it when you just document what each element in the tuple is, rather than writing your own struct/making people look up the struct definition.
Tuples will be easier to write - no need to create a new struct for every function that returns something. Documentation about what goes where will go to the function documentation, which will be needed anyway. To use the function one will need to read the function documentation in any case and the tuple will be explained there.
I agree with you 100% Roddy.
To return multiple values from a method, you have several options other than tuples, which one is best depends on your case:
Creating a new struct. This is good when the multiple values you're returning are related, and it's appropriate to create a new abstraction. For example, I think "divide_result" is a good general abstraction, and passing this entity around makes your code much clearer than just passing a nameless tuple around. You could then create methods that operate on the this new type, convert it to other numeric types, etc.
Using "Out" parameters. Pass several parameters by reference, and return multiple values by assigning to the each out parameter. This is appropriate when your method returns several unrelated pieces of information. Creating a new struct in this case would be overkill, and with Out parameters you emphasize this point, plus each item gets the name it deserves.
Tuples are Evil.
I have an array of constant data like following:
enum Language {GERMAN=LANG_DE, ENGLISH=LANG_EN, ...};
struct LanguageName {
ELanguage language;
const char *name;
};
const Language[] languages = {
GERMAN, "German",
ENGLISH, "English",
.
.
.
};
When I have a function which accesses the array and find the entry based on the Language enum parameter. Should I write a loop to find the specific entry in the array or are there better ways to do this.
I know I could add the LanguageName-objects to an std::map but wouldn't this be overkill for such a simple problem? I do not have an object to store the std::map so the map would be constructed for every call of the function.
What way would you recommend?
Is it better to encapsulate this compile time constant array in a class which handles the lookup?
If the enum values are contiguous starting from 0, use an array with the enum as index.
If not, this is what I usually do:
const char* find_language(Language lang)
{
typedef std::map<Language,const char*> lang_map_type;
typedef lang_map_type::value_type lang_map_entry_type;
static const lang_map_entry_type lang_map_entries[] = { /*...*/ }
static const lang_map_type lang_map( lang_map_entries
, lang_map_entries + sizeof(lang_map_entries)
/ sizeof(lang_map_entries[0]) );
lang_map_type::const_iterator it = lang_map.find(lang);
if( it == lang_map.end() ) return NULL;
return it->second;
}
If you consider a map for constants, always also consider using a vector.
Function-local statics are a nice way to get rid of a good part of the dependency problems of globals, but are dangerous in a multi-threaded environment. If you're worried about that, you might rather want to use globals:
typedef std::map<Language,const char*> lang_map_type;
typedef lang_map_type::value_type lang_map_entry_type;
const lang_map_entry_type lang_map_entries[] = { /*...*/ }
const lang_map_type lang_map( lang_map_entries
, lang_map_entries + sizeof(lang_map_entries)
/ sizeof(lang_map_entries[0]) );
const char* find_language(Language lang)
{
lang_map_type::const_iterator it = lang_map.find(lang);
if( it == lang_map.end() ) return NULL;
return it->second;
}
There are three basic approaches that I'd choose from. One is the switch statement, and it is a very good option under certain conditions. Remember - the compiler is probably going to compile that into an efficient table-lookup for you, though it will be looking up pointers to the case code blocks rather than data values.
Options two and three involve static arrays of the type you are using. Option two is a simple linear search - which you are (I think) already doing - very appropriate if the number of items is small.
Option three is a binary search. Static arrays can be used with standard library algorithms - just use the first and first+count pointers in the same way that you'd use begin and end iterators. You will need to ensure the data is sorted (using std::sort or std::stable_sort), and use std::lower_bound to do the binary search.
The complication in this case is that you'll need a comparison function object which acts like operator< with a stored or referenced value, but which only looks at the key field of your struct. The following is a rough template...
class cMyComparison
{
private:
const fieldtype& m_Value; // Note - only storing a reference
public:
cMyComparison (const fieldtype& p_Value) : m_Value (p_Value) {}
bool operator() (const structtype& p_Struct) const
{
return (p_Struct.field < m_Value);
// Warning : I have a habit of getting this comparison backwards,
// and I haven't double-checked this
}
};
This kind of thing should get simpler in the next C++ standard revision, when IIRC we'll get anonymous functions (lambdas) and closures.
If you can't put the sort in your apps initialisation, you might need an already-sorted boolean static variable to ensure you only sort once.
Note - this is for information only - in your case, I think you should either stick with linear search or use a switch statement. The binary search is probably only a good idea when...
There are a lot of data items to search
Searches are done very frequently (many times per second)
The key enumerate values are sparse (lots of big gaps) - otherwise, switch is better.
If the coding effort were trivial, it wouldn't be a big deal, but C++ currently makes this a bit harder than it should be.
One minor note - it may be a good idea to define an enumerate for the size of your array, and to ensure that your static array declaration uses that enumerate. That way, your compiler should complain if you modify the table (add/remove items) and forget to update the size enum, so your searches should never miss items or go out of bounds.
I think you have two questions here:
What is the best way to store a constant global variable (with possible Multi-Threaded access) ?
How to store your data (which container use) ?
The solution described by sbi is elegant, but you should be aware of 2 potential problems:
In case of Multi-Threaded access, the initialization could be skrewed.
You will potentially attempt to access this variable after its destruction.
Both issues on the lifetime of static objects are being covered in another thread.
Let's begin with the constant global variable storage issue.
The solution proposed by sbi is therefore adequate if you are not concerned by 1. or 2., on any other case I would recommend the use of a Singleton, such as the ones provided by Loki. Read the associated documentation to understand the various policies on lifetime, it is very valuable.
I think that the use of an array + a map seems wasteful and it hurts my eyes to read this. I personally prefer a slightly more elegant (imho) solution.
const char* find_language(Language lang)
{
typedef std::map<Language, const char*> map_type;
typedef lang_map_type::value_type value_type;
// I'll let you work out how 'my_stl_builder' works,
// it makes for an interesting exercise and it's easy enough
// Note that even if this is slightly slower (?), it is only executed ONCE!
static const map_type = my_stl_builder<map_type>()
<< value_type(GERMAN, "German")
<< value_type(ENGLISH, "English")
<< value_type(DUTCH, "Dutch")
....
;
map_type::const_iterator it = lang_map.find(lang);
if( it == lang_map.end() ) return NULL;
return it->second;
}
And now on to the container type issue.
If you are concerned about performance, then you should be aware that for small data collection, a vector of pairs is normally more efficient in look ups than a map. Once again I would turn toward Loki (and its AssocVector), but really I don't think that you should worry about performance.
I tend to choose my container depending on the interface I am likely to need first and here the map interface is really what you want.
Also: why do you use 'const char*' rather than a 'std::string'?
I have seen too many people using a 'const char*' like a std::string (like in forgetting that you have to use strcmp) to be bothered by the alleged loss of memory / performance...
It depends on the purpose of the array. If you plan on showing the values in a list (for a user selection, perhaps) the array would be the most efficient way of storing them. If you plan on frequently looking up values by their enum key, you should look into a more efficient data structure like a map.
There is no need to write a loop. You can use the enum value as index for the array.
I would make an enum with sequential language codes
enum { GERMAN=0, ENGLISH, SWAHILI, ENOUGH };
The put them all into array
const char *langnames[] = {
"German", "English", "Swahili"
};
Then I would check if sizeof(langnames)==sizeof(*langnames)*ENOUGH in debug build.
And pray that I have no duplicates or swapped languages ;-)
If you want fast and simple solution , Can try like this
enum ELanguage {GERMAN=0, ENGLISH=1};
static const string Ger="GERMAN";
static const string Eng="ENGLISH";
bool getLanguage(const ELanguage& aIndex,string & arName)
{
switch(aIndex)
{
case GERMAN:
{
arName=Ger;
return true;
}
case ENGLISH:
{
arName=Eng;
}
default:
{
// Log Error
return false;
}
}
}