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!
Related
So I have a huge amount of classes (20+ that I want to store into a map array as such:
mapArray['ClassName'] = new ClassName();
I thought about doing something like
App::setup() {
mapArray['ClassName1'] = new ClassName1();
mapArray['ClassName2'] = new ClassName2();
mapArray['ClassName3'] = new ClassName3();
}
However I think that is inefficient. I was thinking on how I would go about doing this, I was thinking to use preprocessor directives. Something like this
#define DECLARE_CLASS(ClassName)
mapArray[ClassName] = new ClassName();
However, with this approach I would still need to to call that multiple time within the same function or something.
How would I go about adding all the classes to the same array but without calling the same code multiple time within the same function? So that the code isn't repetitive.
Using
App::setup() {
mapArray['ClassName1'] = new ClassName1();
mapArray['ClassName2'] = new ClassName2();
mapArray['ClassName3'] = new ClassName3();
}
is not a good idea (even after you fix the incorrect syntax of trying to use single quotes to define a string). It breaks the Open/Closed Principle. If you want to add ClassNameN to your system, you have to come back to modify a working function.
It's better to use a registration mechanism. Declare a function, registerObject, as:
App::registerObject(std::string const& name, BaseClass* ptr);
and implement it as:
static std::map<std::string, BaseClass*>& getClassMap()
{
static std::map<std::string, BaseClass*> theMap;
return theMap;
}
App::registerObject(std::string const& name, BaseClass* ptr)
{
getClassMap()[name] = ptr;
}
and then, in the source file that contains the implementation of ClassNameN, make sure to call
App::registerObject("ClassNameN", new ClassNameN());
One way to register:
Use a helper class called Initializer, which is defined in the .cpp file.
Make the call to App::registerObject in the constructor of `Initializer.
Create a file scoped static instance of Initializer in the .cpp file
ClassName1.cpp:
#include "ClassName1.hpp"
// You can use anonymous namespace but I prefer to use a named
// namespace. It makes names of the typeinfo object clearer.
namespace ClassName1NS
{
struct Initializer
{
Initializer();
};
}
using namespace ClassName1NS;
static Initializer initializer
Initializer::Initializer()
{
App::registerObject("ClassName1", new ClassName1());
}
My goal is to access a class that is passed in as a parameter inside of myFunction.
Here's what I'm trying to do:
void myFunction(string myString)
{
callFunctionOn(OuterType::InnerType::myString);
}
I'm trying to call some function on something that's in a type. For example, my code in some other file might look like:
namespace OuterType {
namespace InnerType {
//stuff here
}
}
However, using myString in that way doesn't work. If myString holds the value "class1", then I want that callFunctionOn part to be interpreted as
callFunctionOn(OuterType::InnerType::class1);
I feel like this is super simple, but I've been programming all day and my mind grows tired...
SOLVED: It looks like in order to this in this way, I'd need a language with reflection. To solve this I took a different approach to the problem and passed in a pointer to the class instead.
C++ doesn't have reflection built in, but it does have pointers to data, functions, and class members. So you can use a std::map or unordered_set to find the pointer with a particular name (you have to add all the name/pointer pairs into the map beforehand).
Your solution is likely to look something like:
namespace Outer
{
namespace Inner
{
void funcA( void ) { std::cout << "called funcA" << std::endl; }
std::map< std::string, void (*)(void) > members;
}
}
// in some initialization function
Outer::Inner::members["funcA"] = &Outer::Inner::funcA;
// later
std::string myString = "funcA";
void (*f)(void) = Outer::Inner::members[myString]; // lookup function by name
(*f)(); // call function via its pointer
Of course the type of the pointer will probably need to change to meet your application requirements.
You're trying to access a variable based on a run-time string that contains its name? That's not possible; the names of variables disappear after compilation and linking. (Except insofar as they are kept around to facilitate debugging).
Do you mean :
OuterType::InnerType::callFunctionOn(myString);
maybe this idea: operator() can take parameters, wrapping it in a class ine can make calls that are resolved in the overloaded operator() based on its parameters.
template<typename TypeSig, class InstanceOf, typename NA,typename Args>
class FuncMap {
public:
typedef TypeSig (InstanceOf:: *cbMethod) ( NA, Args );
FuncMap( InstanceOf & cInst, cbMethod cbM ) : mcInst(cInst) {mcbM = cbM;}
TypeSig operator() ( NA na, Args args) {return (mcInst.*mcbM)(na, args);}
private:
InstanceOf & mcInst;
cbMethod mcbM;
};
you need to build a map of runtime string values as keys and pointers to instance methods as seen above. i used this for re-dispatch tracing and custom runtime dispatch with lesser than RTTI overhead.
this allows you to have default, if no key found, or other logic as you wish.
I am developing a list in which I have used some protected variables count, entry[maxlist] etc.
List.h
class List
{
public:
//etc etc
protected:
int count;
int entry[maxlist];
};
Sortable_list.h
typedef Key Record;
class Sortable_list:public List<Record>
{
void selection_sort()
{
for(int position=count-1;position>0;i--) // Count is not declared in the scope
{
int max=max_key(0, position);
swap(max, position);
}
}
};
Is something wrong with inheriting the List to Sortable List? Why is it showing count out of scope?
#Edit: After seeing your whole code it becomes clearer. You're having ambiguities because of your includes, it will compile with msvc, because it handles such cases silently, but for g++ you should explicitly state that count is from this class, by doing this->count. You also had problems because of std::range_error, which could be avoided by removing using namespace std or replacing range_error with ::range_error which will indicate that you want the global scope. Another problem with your code is that, you were using an undefined variable i in your Sortable_list. The fixed code that compiles with g++ and msvc: http://codepad.org/7V70rNqf
I don't want to sound rude, but I strongly suggest you read a book on C++, your current code is very anti-idiomatic, and could be made generic with a smaller amount of code.
Why don't you use sort function template from <algorithm> header? All you need to write just one small Compare function.
Look like your List is not a template class, so List< Typename > doesn't exist ..
Also, you can use std::set<T> as a template class for sorted container => http://www.sgi.com/tech/stl/set.html
How can I call a function and keep my constructor private? If I make the class static, I need to declare an object name which the compiler uses to call the constructor, which it cannot if the constructor is private (also the object would be extraneous). Here is the code I am attempting to use (it is not compilable):
I want to keep the constructor private because I will later be doing a lot of checks before adding an object, modifying previous objects when all submitted variables are not unique rather than creating new objects.
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
#include <map>
using namespace std;
using namespace tr1;
class Referral
{
public:
string url;
map<string, int> keywords;
static bool submit(string url, string keyword, int occurrences)
{
//if(Referrals.all.size == 0){
// Referral(url, keyword, occurrences);
//}
}
private:
list<string> urls;
Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(this);
}
};
struct All
{
list<Referral> all;
}Referrals;
int main()
{
Referral.submit("url", "keyword", 1);
}
What's wrong with having a private constructor and a static factory method?
class Example {
Example() { ... }
public:
static Example CreateExample() {
return Example();
}
};
Based on your main code I think what you're shooting for is a singleton, which would look something like:
class Referral
{
private:
Referral()
{
//...
}
public:
static Referral& instance()
{
static Referral instance_s;
return instance_s;
}
bool submit(string url, string keyword, int occurrences)
{
//...
}
};
Then your call in main would look like:
int main()
{
Referral::instance().submit("url", "keyword", 1);
}
Another possibility is that you're looking to keep a list of Referrals around, in which case you can use a struct and a list of them to accomplish what you're looking for:
struct Referral
{
Referral(string url, string keyword, int occurrences) :
url_m(url), keyword_m(keyword), occurrences_m(occurrences)
{ }
string url_m;
string keyword_m;
int occurrences_m;
};
typedef std::vector<Referral> ReferralSet;
Then your call in main would look like:
int main()
{
ReferralSet set;
set.push_back(Referral("url", "keyword", 1));
}
First, you need to make Submit a static function. Then you can just say
Referral::Submit( url, keyword, occurrences );
without creating a Referral instance.
Then, in your Submit function, you're only creating a temporary Referral object that disappears almost immediately. Probably what you want to do is create an instance dynamically with new. Depending on how you want to manage this, you may want to move the code pushing onto the list into Submit.
Lastly, I would make your list of Referral instances a static member variable rather than how you have it now.
(Also, passing those string arguments by reference would probably be a good idea.)
While the whole code has some smell around, you can make it work just by making slight changes that are unrelated to your question.
To make it compile, I have removed the regex include (I am not using a compiler with C++0x support) and the 'using namespace tr1'. Move the constructor implementation after the definition of the Referral global object. Change the . for a :: in the main function when you refer to a static method.
// changes...
//#include <regex>
...
//using namespace tr1;
...
class Referral {
...
Referral(string url, string keyword, int occurrences); // added ; moved the implementation bellow the Referrals variable definition
...
struct All {
...
} Referrals;
// added constructor implementation here (Referrals global must be defined before use):
Referral::Referral(string url, string keyword, int occurrences)
{
url = url;
keywords[keyword] = occurrences;
Referrals.all.push_back(*this); // added dereference, this is of type Referral*, not Referral
}
int main()
{
Referral::submit("url","keyword",1);
}
Now, from a design point of view the code has a stench to it. If really want to have a global list where you add your Referral objects, consider making it a private static attribute of the Referral class so that you can have a little more control over it (only methods in the Referral class could break the contents). Make all your attributes private and provide only accessors to the functionality that user code will need (read-only access can suffice in most cases). Use initialization lists in your constructors, and initialize all members there in the same order they appear in the class definition.
With all that fixed, it still has some smell to it. The static function creates an instance of the class but the constructor is the one that includes itself in the map (??) It would make a little more sense if the constructor did not interact with the map, and the submit() method would create the object and then include it in the list...
I think you might benefit from expressing what you intend to do, many people here will help you both with design choices and reasons for them.
When I write code like this in VS 2008:
.h
struct Patterns {
string ptCreate;
string ptDelete;
string ptDrop;
string ptUpdate;
string ptInsert;
string ptSelect;
};
class QueryValidate {
string query;
string pattern;
static Patterns pts;
public:
friend class Query;
QueryValidate(const string& qr, const string& ptn):
query(qr), pattern(ptn) {}
bool validate() {
boost::regex rg(pattern);
return boost::regex_match(query, rg);
}
virtual ~QueryValidate() {}
};
I then initialize my structure like this:
.cpp
string QueryValidate::pts::ptCreate = "something";
string QueryValidate::pts::ptDelete = "something";
//...
The compiler gives the following errors:
'Patterns': the symbol to the left of a '::' must be a type 'ptSelect'
: is not a member of 'QueryValidate'
What am I doing wrong? Is this a problem with Visual Studio or with my code? I know that static members except for const ones must be defined outside the class they were declared in.
You're trying to create a non-static member (ptCreate) of a static member (pts). This won't work like this.
You got two options, either use a struct initializer list for the Patterns class.
Patterns QueryValidate::pts = {"CREATE", "DELETE"}; // etc. for every string
Or, much safer (and better in my opinion), provide a constructor in Patterns and call that one.
struct Patterns {
Patterns() { /*...*/ }
/* ... */
}
On a side not, your code wouldn't work in any C++ compiler, it's not a conflict with Visual Studio things.
You can only initialize the structure as a whole, as in:
Patterns QueryValidate::pts = { "something", "something", ... };
This isn't valid C++. In the cpp file you're declaring parts of the static structure "QueryValidate::pts", but that's not allowed: you've got to declare the whole structure, like so:
Patterns QueryValidate::pts;
if you want members to be initialized, you either initialize them in another method, or add a constructor to Patterns that takes whatever initialization arguments you want.
I'm not real sure what you are trying to do here. It looks kind of like you are trying to declare and initialize each field in pts separately, rather than declare pts once as a single object. I'm really surprised VS lets you do that.
What worked for me in gcc was the following:
Patterns QueryValidate::pts;
void foo () {
QueryValidate::pts.ptCreate = "something";
QueryValidate::pts.ptDelete = "something";
}