Reflection in c++ - print all the defined strings in a class - c++

Assume I have:
#include <iostream>
class Greeter
{
public:
void printEm() {...}
private:
std::string a = "Hello!";
std::string b = "Hi!";
int IAmNotAString = 0;
};
What is the simplest way to get printEm to print all the defined strings in Greeter, and further, should someone define a new string, print that one too? Any boost library is fine - I have some experience with Fusion, but I don't know how it could automatically infer which members are strings.

C++ does not have any reflection. If you want to do this with macros, you would also have to define your member variables using specially crafted macros. A simple idea would be each macro would add the member to am internal vector and your printEm would just iterate through this vector. It's not the most elegant solution but it's how various libraries work.

Related

Adressing variables by variable names [duplicate]

This question already has answers here:
Iterate through Struct and Class Members [duplicate]
(6 answers)
Closed 2 years ago.
I am currently writing a ROS 2 node to pass values from a PLC through ROS to a visualization:
PLC System --> ROS --> Visualization
Since ROS should only pass on the data, I want to be able to configure the interface here with as little effort as possible. The idea, which can be implemented best with ROS, would be a config-file(.msg file), in which the designation of the variables and their type is entered. Everything else is then derived from this.
The problem I inevitably run into with this: In ROS data are passed on over so-called messages. These messages are defined via structs and are automatically generated from my config-file. To assign values to the variables from the struct, I don't want to address every single one hardcoded in the program, but rather iterate through the struct using the known names.
TLNR: Can variables be addressed with variable variable names?
I know that the whole thing sounds a bit confusing. I hope the following example will clarify what I mean:
#include <vector>
#include <string>
struct MsgFile
{
int someVariable;
int someOtherVariable;
};
using namespace std;
class Example
{
public:
vector<string> variableNames{"someVariable", "someOtherVariable"};
MsgFile message;
void WriteVariables()
{
for (auto const &varName : variableNames)
{
message."varName" = 0; //<-- pseudo code of what I'm thinking of
}
}
};
Regards
Tillman
You cannot use variable names like that. There are no variable names at runtime. If you want a mapping between names (strings) and variables, you need to add that yourself.
If your "variables" are of same type, eg int, you can use a map:
#include <vector>
#include <string>
#include <unordered_map>
using MsgFile = std::unordered_map<std::string,int>;
struct Example {
std::vector<std::string> variableNames{"someVariable", "someOtherVariable"};
MsgFile message;
void WriteVariables() {
for (auto const &varName : variableNames) {
message[varName] = 0; // add an entry { varName, 0 } to the map
// (or updates then entry for key==varName when it already existed)
}
}
};
If you only need the string representation to access it (but not for printing etc) you can consider to use an enum as key instead. At least I'd define some constants like const std::string some_variable{"some_variable"}, to avoid typos going unnoticed (perhaps the variableNames is supposed to be const (and static?)).
As far as I know there is no standard way to do this, I would choose another way to store the data ( I mean not in struct ), but if you are adamant here is an answered question:
Get list of C structure members

Declare a "list" of constant in a class

I would like to create a list of constant within my class but I don't know how tto do it properly.
First I tried to but it in an Enum like that:
class CMyClass{
public:
enum EKeyword
{
E_PARAM1 = "myString1",
E_PARAM2 = "myString2",
...
};
but it seems that it is not possible (-> error C2057: expected constant expression)
I know that I could just declare one by one each of my constant with a #define or using "static const ..." declaration but I like the use of : EKeyword.E_PARAM1 to get my string and I don't want to set those constants global.
Any recommandations ?
You cannot make an enum with a string representation in c++. You will need a list of strings. If you wan't to force them to be referenced inside a structure (like an enum class) add them to a struct:
class CMyClass {
public:
struct EKeyword {
static constexpr char const* PARAM_1 = "myString1";
...
private:
EKeyword(); // Disables the ability to construct an EKeyword struct.
};
...
Then use within the class will be like:
EKeyword::PARAM_1
and outside the class will be:
CMyClass::EKeyword::PARAM_1
If you are limited to c++03 you will need to create the string values in a cpp file:
// .hpp
class CMyClass {
...
struct EKeyword {
static char const* PARAM_1;
...
// .cpp
char const* CMyClass::EKeyword::PARAM_1 = "myString1";
Here is a live example.
Following this comment from the asker:
I'm creating a list of keyword that I will looking for in a file and
then exchange the keyword with its value. ex: find the keyword
"$temperature" -> replace the word with "28°C"
The approach you are suggesting of using named variables, or an enum will be inappropriate for this since C++ has no reflection and variable names are not accessible from the code. What you want is a map - possibly std::map<std::string, std::string>, although higher performance options might be necessary depending on the use case - from the values you want to find to the values you want to replace them with.
The best way to do this would be to read in a file containing the replacement values because then you can modify the replacement values without modifying the code and have a more general solution, but you can otherwise use C++11's unified initialisation lists to populate the map in your code, or perhaps populate them one by one in, for example, a constructor, if unified initialisation isn't suitable for your needs or for some reason C++11 is unavailable to you.
You can then scan through the file finding strings you want to replace and replacing them with the listed replacement. Be careful though, what will you do about overlapping replacement? Do you only check whole words, etc?

C++ Combine enum and string into a map-like variable, able to be used with both int and string

Suppose I have an enum:
enum Types
{
TYPE_ASCENDING,
TYPE_DESCENDING
};
and I use it to it... anywhere in the code. Say if(bla < TYPE_ASCENDING), or with a switch/case. The real enum is much larger.
Whatever the results of the checks (or anything else), it needs to be std::cout in a prettier way to let the user know what happened. So, continuing the if() example, it might be something like this:
if(bla < TYPE_ASCENDING)
std::cout << "Ascending.\n";
All these happen inside a class. My question: is there a way to define some type of variable/STL/anything that would allow storing both enum-like and std::string-like variables, but would also let me use, separately, both types?
One thought was a namespace, but it seems it can't be used inside a class. To exemplify, here's what it would have looked like:
namespace Type
{
enum Types
{
ASCENDING,
DESCENDING
};
std::string s[2] {"Ascending", "Descending"};
};
and it would have been called as Type::ASCENDING for the if(), and Type::s[0] for the string. But, no namespace inside a class, so it's not a solution.
Using std::map only lets me use int as the index, so I can only use this:
std::map<Types, std::string> m {{TYPE_ASCENDING, "Ascending}, {TYPE_DESCENDING, "Descending"}};
as m[0], or m[TYPE_ASCENDING], but I can't call it for it's index to be used inside the if(). For that I have to call the enum, separately, which means I have both an enum and a map, two variables. I need one, unified, to avoid chasing variable names all over the code.
If I use a struct, I can't access directly Struct::TYPE_DESENDING, I need to create an object.
I can use an enum and a std::string array/vector, but that means that, again, I have to call two variables, separately, and I'd like them to be unified.
Is what I want possible?
You don't really have that mechanism in native C++. You can write a map / mapper function.
enum class E
{
ONE,
TWO
};
std::unordered_map<E,std::string> eStrings { {E::ONE,"ONE"},{E::TWO,"two"}};
While this is C++11 you can do the same for older C++ versions
Then you can use this like
std::cout << eStrings[E::ONE];
The issue here is you have to maintain this manually. So when you add a new value to the enum you have to manually add a new entry to the map.
The same would be true for writing a class or functions to have this behavior. You always have to duplicate the code of enum declaration and the mapping to the string.
A solution here would be to use some tool to generate these.
You can define in some file your enum (this is just some random format and only intended for explaining this. Chose whatever you want in your own defenition file)
E
- ONE
- TWO
And then generate the C++ enum and Map in a header and/or cpp file.
enum class <name>
{
<foreach:> <value>,
};
std::unordered_map< <name> ,std::string> eStrings
{
<foreach:> {<name>::<value>,"<value>"},
};
If you don't like having a map this approach is pretty flexible. You can also generate a switch case statement if you like
std::string getString(<name> e)
{
switch(e)
{
<foreach:> case <name>::<value>: return "<value>";
}
}
The syntax here is no standard for anything just some "pseudocode" to visualize the concept. There are several ways to generate c++ code out there. You can choose whatever you want or write your own program for this.
Note:
This is also just a general concept. You can wrap this functioniality / map etc into another class, make it static etc. for optimizations and not put it in global scope.
If you need something more fancy than just a map to lookup the string you can create a class with this concept or another map which does just the reverse lookup. It's more about the fact that you most likely have to generate the code by an external tool.
Reading Hayts answer I see that what I originally wrote may be relevant for the auto generation of code aspect. So I leave it here.
Seeing as regular old enums are implicitly convertible to int (as opposed to enum classes), you can simply use a map<int, string>.
Now, to the interesting part, generating it semi-automatically.
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}
I used a technique known as X-Macros. The premise is that you pass all the argument needed for your enum into the macro. Then you define the macro, depending on how you need the arguments to be used. So firstly:
# define ENUM_DEF(v, s) v,
This just expands the enum token as you'd provide it to a regular enum defintion.
Then, in Things c'tor:
# define ENUM_DEF(v, s) string[v] = s;
It expands to the statement you need to populate the map.
And to address one last point you may have issue with: Do you really have to do all this repetition, retyping ENUM_DEF all the time?
Well, luckily you don't. You can move those statements into their own file, let's call it type_enum.def:
#ifdef ENUM_DEF
ENUM_DEF(TYPE_ASCENDING, "Ascending")
ENUM_DEF(TYPE_DESCENDING, "Descending")
#endif //ENUM_DEF
And the original code becomes:
#include <iostream>
#include <map>
#include <string>
struct Thing {
enum Type {
# define ENUM_DEF(v, s) v,
# include "type_enum.def"
# undef ENUM_DEF
};
std::map<int, std::string> string;
Thing() {
# define ENUM_DEF(v, s) string[v] = s;
# include "type_enum.def"
# undef ENUM_DEF
}
};
int main() {
Thing t;
std::cout << t.string[0];
return 0;
}

Is there a way to apply an action to N C++ class members in a loop over member names (probably via pre-processor)?

The problem:
I have a C++ class with gajillion (>100) members that behave nearly identically:
same type
in a function, each member has the same exact code done to it as other members, e.g. assignment from a map in a constructor where map key is same as member key
This identicality of behavior is repeated across many-many functions (>20), of course the behavior in each function is different so there's no way to factor things out.
The list of members is very fluid, with constant additions and sometimes deletions, some (but not all) driven by changing columns in a DB table.
As you can imagine, this presents a big pain-in-the-behind as far as code creation and maintenance, since to add a new member you have to add code to every function
where analogous members are used.
Example of a solution I'd like
Actual C++ code I need (say, in constructor):
MyClass::MyClass(SomeMap & map) { // construct an object from a map
intMember1 = map["intMember1"];
intMember2 = map["intMember2"];
... // Up to
intMemberN = map["intMemberN"];
}
C++ code I want to be able to write:
MyClass::MyClass(SomeMap & map) { // construct an object from a map
#FOR_EACH_WORD Label ("intMember1", "intMember2", ... "intMemberN")
$Label = map["$Label"];
#END_FOR_EACH_WORD
}
Requirements
The solution must be compatible with GCC (with Nmake as make system, if that matters).
Don't care about other compilers.
The solution can be on a pre-processor level, or something compilable. I'm fine with either one; but so far, all of my research pointed me to the conclusion that the latter is just plain out impossible in C++ (I so miss Perl now that I'm forced to do C++ !)
The solution must be to at least some extent "industry standard" (e.g. Boost is great, but a custom Perl script that Joe-Quick-Fingers created once and posted on his blog is not. Heck, I can easily write that Perl script, being much more of a Perl expert than a C++ one - I just can't get bigwigs in Software Engineering at my BigCompany to buy into using it :) )
The solution should allow me to declare a list of IDs (ideally, in only one header file instead of in every "#FOR_EACH_WORD" directive as I did in the example above)
The solution must not be limited to "create an object from a DB table" constructor. There are many functions, most of them not constructors, that need this.
A solution of "Make them all values in a single vector, and then run a 'for' loop across the vector" is an obvious one, and can not be used - the code's in a library used by many apps, the members are public, and re-writing those apps to use vector members instead of named members is out of the question, sadly.
Boost includes a great preprocessor library that you can use to generate such code:
#include <boost/preprocessor/repetition.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/cat.hpp>
typedef std::map<std::string, int> SomeMap;
class MyClass
{
public:
int intMember1, intMember2, intMember3;
MyClass(SomeMap & map)
{
#define ASSIGN(z,n,_) BOOST_PP_CAT(intMember, n) = map[ BOOST_PP_STRINGIZE(BOOST_PP_CAT(intMember, n))];
BOOST_PP_REPEAT_FROM_TO(1, 4, ASSIGN, nil)
}
};
Boost.Preprocessor proposes many convenient macros to perform such operations. Bojan Resnik already provided a solution using this library, but it assumes that every member name is constructed the same way.
Since you explicitely required the possibily to declare a list of IDs, here is a solution that should better fulfill your needs.
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>
// sequence of member names (can be declared in a separate header file)
#define MEMBERS (foo)(bar)
// macro for the map example
#define GET_FROM_MAP(r, map, member) member = map[BOOST_PP_STRINGIZE(member)];
BOOST_PP_SEQ_FOR_EACH(GET_FROM_MAP, mymap, MEMBERS)
// generates
// foo = mymap["foo"]; bar = mymap["bar];
-------
//Somewhere else, we need to print all the values on the standard output:
#define PRINT(r, ostream, member) ostream << member << std::endl;
BOOST_PP_SEQ_FOR_EACH(PRINT, std::cout, MEMBERS)
As you can see, you just need to write a macro representing the pattern you want to repeat, and pass it to the BOOST_PP_SEQ_FOR_EACH macro.
You could do something like this: create an adapter class or modify the existing class to have a vector of pointers to those fields, add the addresses of all member variables in question to that vector in the class constructor, then when needed run the for-loop on that vector. This way you don't (or almost don't) change the class for external users and have a nice for-loop capability.
Of course, the obvious question is: Why do you have a class with 100 members? It doesn't really seem sane.
Assuming it is sane nevertheless -- have you looked at boost preprocessor library? I have never used it myself (as one friend used to say: doing so leads to the dark side), but from what I heard it should be the tool for the job.
Surreptitiously use perl on your own machine to create the constructor. Then ask to increase your salary since you're succesfully maintaining such a huge chunk of code.
You could use the preprocessor to define the members, and later use the same definition to access them:
#define MEMBERS\
MEMBER( int, value )\
SEP MEMBER( double, value2 )\
SEP MEMBER( std::string, value3 )\
struct FluctuatingMembers {
#define SEP ;
#define MEMBER( type, name ) type name
MEMBERS
#undef MEMBER
#undef SEP
};
.. client code:
FluctuatingMembers f = { 1,2., "valuesofstringtype" };
std::cout <<
#define SEP <<
#define MEMBER( type, name ) #name << ":" << f.##name
MEMBERS;
#undef MEMBER
#undef SEP
It worked for me, but is hard to debug.
You can also implement a visitor pattern based on pointer-to-members. After the preprocessor solution, this one turns out way more debuggeable.
struct FluctuatingMembers {
int v1;
double v2;
std::string v3;
template<typename Visitor> static void each_member( Visitor& v );
};
template<typename Visitor> void FluctuatingMembers::each_member( Visitor& v ) {
v.accept( &FluctuatingMembers::v1 );
v.accept( &FluctuatingMembers::v2 );
v.accept( &FluctuatingMembers::v3 );
}
struct Printer {
FluctuatingMembers& f;
template< typename pt_member > void accept( pt_member m ) const {
std::cout << (f::*m) << "\n";
}
};
// you can even use this approach for visiting
// multiple objects simultaneously
struct MemberComparer {
FluctuatingMembers& f1, &f2;
bool different;
MemberComparer( FluctuatingMembers& f1, FluctuatingMembers& f2 )
: f1(f1),f2(f2)
,different(false)
{}
template< typename pt_member > void accept( pt_member m ) {
if( (f1::*m) != (f2::*m) ) different = true;
}
};
... client code:
FluctuatingMembers object1 = { 1, 2.2, "value2" }
, object2 = { 1, 2.2, "valuetoo" };
Comparer compare( object1, object2 );
FluctuatingMembers::each_member( compare );
Printer pr = { object1 };
FluctuatingMembers::each_member( pr );
Why not do it at run time? (I really hate macro hackery)
What you really are asking for, in some sense, is class metadata.
So I would try something like:
class AMember{
......
};
class YourClass{
AMember member1;
AMember member2;
....
AMember memberN;
typedef AMember YourClass::* pMember_t;
struct MetaData : public std::vector<std::pair<std::string,pMember_t>>{
MetaData(){
push_back(std::make_pair(std::string("member1"),&YourClass::member1));
...
push_back(std::make_pair(std::string("memberN"),&YourClass::memberN));
}
};
static const MetaData& myMetaData() {
static const MetaData m;//initialized once
return m;
}
YourClass(const std::map<std::string,AMember>& m){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = m[i->first];
}
}
YourClass(const std::vector<std::pair<std::string,pMember_t>>& m){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = m[i->first];
}
}
};
(pretty sure I've got the syntax right but this is a machinery post not a code post)
RE:
in a function, each member has the same exact code done to it as other members, e.g. assignment from a map in a constructor where map key is same as member key
this is handled above.
RE:
The list of members is very fluid, with constant additions and sometimes deletions, some (but not all) driven by changing columns in a DB table.
When you add a new AMember, say newMember, all you have to do is update the MetaData constructor with an:
push_back(make_pair(std::string("newMember"),&YourClass::newMember));
RE:
This identicality of behavior is repeated across many-many functions (>20), of course the behavior in each function is different so there's no way to factor things out.
You have the machinery to apply this same idiom to build the functions
eg: setAllValuesTo(const AMember& value)
YourClass::setAllValuesTo(const AMember& value){
const MetaData& md = myMetaData();
for(MetaData::const_iterator i = md.begin();i!= md.end();++i){
this->*(i->second) = value;
}
}
If you are a tiny bit creative with function pointers or template functionals you can factor out the mutating operation and do just about anything you want to YourClass' AMember's on a collection basis. Wrap these general functions (that may take a functional or function pointer) to implement your current set of 20 public methods in the interface.
If you need more metadata just augment the codomain of the MetaData map beyond a pointer to member. (Of course the i->second above would change then)
Hope this helps.
You can do something like his:
#define DOTHAT(m) m = map[#m]
DOTHAT(member1); DOTHAT(member2);
#undef DOTHAT
That doesn't fully fit your description, but closest to it that saves you typing.
Probably what I'd look to do would be to make use of runtime polymorphism (dynamic dispatch). Make a parent class for those members with a method that does the common stuff. The members derive their class from that parent class. The ones that need a different implementation of the method implement their own. If they need the common stuff done too, then inside the method they can downcast to the base class and call its version of the method.
Then all you have to do inside your original class is call the member for each method.
I would recommend a small command-line app, written in whatever language you or your team are most proficient in.
Add some kind of template language to your source files. For something like this, you don't need to implement a full-fledged parser or anything fancy like that. Just look for an easily-identified character at the beginning of a line, and some keywords to replace.
Use the command-line app to convert the templated source files into real source files. In most build systems, this should be pretty easy to do automatically by adding a build phase, or simply telling the build system: "use MyParser.exe to handle files of type *.tmp"
Here's an example of what I'm talking about:
MyClass.tmp
MyClass::MyClass(SomeMap & map) { // construct an object from a map
▐REPLACE_EACH, LABEL, "intMember1", "intMember2, ... , "intMemberN"
▐ LABEL = map["$Label"];
}
I've used "▐" as an example, but any character that would otherwise never appear as the first character on a line is perfectly acceptable.
Now, you would treat these .tmp files as your source files, and have the actual C++ code generated automatically.
If you've ever heard the phrase "write code that writes code", this is what it means :)
There are already a lot of good answers and ideas here, but for the sake of diversity I'll present another.
In the code file for MyClass would be:
struct MemberData
{
size_t Offset;
const char* ID;
};
static const MemberData MyClassMembers[] =
{
{ offsetof(MyClass, Member1), "Member1" },
{ offsetof(MyClass, Member2), "Member2" },
{ offsetof(MyClass, Member3), "Member3" },
};
size_t GetMemberCount(void)
{
return sizeof(MyClassMembers)/sizeof(MyClassMembers[0]);
}
const char* GetMemberID(size_t i)
{
return MyClassMembers[i].ID;
}
int* GetMemberPtr(MyClass* p, size_t i) const
{
return (int*)(((char*)p) + MyClassMembers[i].Offset);
}
Which then makes it possible to write the desired constructor as:
MyClass::MyClass(SomeMap& Map)
{
for(size_t i=0; i<GetMemberCount(); ++i)
{
*GetMemberPtr(i) = Map[GetMemberID(i)];
}
}
And of course, for any other functions operating on all the members you would write similar loops.
Now there are a few issues with this technique:
Operations on members use a runtime loop as opposed to other solutions which would yield an unrolled sequence of operations.
This absolutely depends on each member having the same type. While that was allowed by OP, one should still evaluate whether or not that might change in the future. Some of the other solutions don't have this restriction.
If I remember correctly, offsetof is only defined to work on POD types by the C++ standard. In practice, I've never seen it fail. However I haven't used all the C++ compilers out there. In particular, I've never used GCC. So you would need to test this in your environment to ensure it actually works as intended.
Whether or not any of these are problems is something you'll have to evaluate against your own situation.
Now, assuming this technique is usable, there is one nice advantage. Those GetMemberX functions can be turned into public static/member functions of your class, thus providing this generic member access to more places in your code.
class MyClass
{
public:
MyClass(SomeMap& Map);
int Member1;
int Member2;
int Member3;
static size_t GetMemberCount(void);
static const char* GetMemberID(size_t i);
int* GetMemberPtr(size_t i) const;
};
And if useful, you could also add a GetMemberPtrByID function to search for a given string ID and return a pointer to the corresponding member.
One disadvantage with this idea so far is that there is a risk that a member could be added to the class but not to the MyClassMembers array. However, this technique could be combined with xtofl's macro solution so that a single list could populate both the class and the array.
changes in the header:
#define MEMBERS\
MEMBER( Member1 )\
SEP MEMBER( Member2 )\
SEP MEMBER( Member3 )\
class MyClass
{
public:
#define SEP ;
#define MEMBER( name ) int name
MEMBERS;
#undef MEMBER
#undef SEP
// other stuff, member functions, etc
};
and changes in the code file:
const MemberData MyClassMembers[] =
{
#define SEP ,
#define MEMBER( name ) { offsetof(MyClass, name), #name }
MEMBERS
#undef MEMBER
#undef SEP
};
Note: I have left error checking out of my examples here. Depending on how this would be used, you might want to ensure the array bounds are not overrun with debug mode asserts and/or release mode checks that would return NULL pointers for bad indexes. Or some use of exceptions if appropriate.
Of course, if you aren't worried about error checking the array bounds, then GetMemberPtr could actually be changed into something else that would return a reference to the member.

Populate a static member container in c++

I've got a static class member which is some container, like
(Foo.h)
class Foo
{
...
private:
static list<string> s_List;
}
I need to populate the list with a number of specific values. Actually it should be also const, but that might overcomplicate the problem further.
All the class member functions are static, so initializing it in a constructor doesn't make sense.
a common solution is to do something like this:
// header
class Foo
{
...
private:
static list<string> s_List;
}
// cpp
list<string> init()
{
list<string> tmp;
... fill tmp with strings
return tmp;
}
list<string> Foo::s_List(init());
the other method is like Neil Butterworth suggested.
Another alternative is to create a simple initialiser class:
list <string> Foo::s_List;
struct Init {
Init() {
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
}
};
static Init doInit;
Note that, as the list is private, this will probably require you to make Init a friend of Foo. It's also often convenient to make such classes be contained by the class they are initialising.
However, I just re-read your question and another thought occurs - if the list is const, you will presumably not be changing it, in which case a simple array of strings, initialised with the strings in sorted order may be a better solution. It will certainly be faster to search (using std::binary_search) than a list, and can of course be easily initialised.
If your compiler supports C++0x, this is actually trivial to accomplish.
#include <iostream>
#include <list>
class Foo
{
public:
static std::list<std::string> s_List;
};
std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"};
int main()
{
for(const std::string& str : Foo::s_List)
std::cout << str << std::endl;
return 0;
}
This works for both const and non-const static members. I've tested this snippet with clang-4.2, gcc-4.7, gcc-4.6, and gcc-4.5. Gcc-4.5 does not support the updated for syntax, so you'd have to use a traditional for loop with iterators. Also, don't forget to pass the -std=c++0x flag to the compiler. I'm reasonably confident Visual Studio supports this as well, but I don't know for sure and don't know which versions.
It depends on what values you need to put in that list. Are they static or do they require some form of computation?
If they are static, you can do this:
namespace {
const char* const initVals[] = { "A", "B", "C" };
}
list<string> Foo::s_list(initVals, initVals + 3);
one possible solution would be to use an accessor method that checks to see if it is initialized, and does so if it isn't.
The ways I(the author of the question) have vainly tried to do this.
I tried to do smth like (in Foo.cpp):
list<string> Foo::s_List = list<string>();
Foo::s_List.insert("apple");
Foo::s_List.insert("bannana");
Foo::s_List.insert("grapes");
But that gives a compiler error.
Then I thought of making an Initialize() method and calling it right from the code
void Foo::Initialize()
{
s_List.insert("rats");
s_List.insert("cats");
}
Foo::Initialize();
// error: compiler considers it to be a redefenition of the method, not a call.
The only viable idea left (havent yet tried) would be to check if the list is empty in each method that uses it, and if it's the case, call Initialize(). But that's ugly!