I've read all the suggestions I've found in the following links
c++ typedef another class's enum?
http://forums.devarticles.com/c-c-help-52/how-to-use-enum-when-it-is-in-another-class-17773.html
http://forums.codeguru.com/showthread.php?t=435215
How do I use the Enum value from a class in another part of code?
but still wasn't able to find a solution to my problem:
I need to construct an object of class A (whose constructor expects as an input
parameter an enumerative type of that class) from inside a function of an object of class B
Here are the code snippets:
File A.h:
Class A{
public:
enum FileType{TEXT, BIN};
/*! This constructor initializes the data from a given file
* (binary, text, image).
*/
A(const std::string& filename, FileType type);
}
File A.cpp:
A::A(const std::string& filename, FileType type){
...
}
File B.h:
Class B{
private:
A objectOfClassA;
public:
enum FileType{TEXT = A::FileType::TEXT, BIN = A::FileType::BIN}; //<----THIS IS NOT WORKING!
foo_func(const std::string& filename, FileType type);
}
File B.cpp:
void B::foo_func(const std::string& filename, FileType type){
this->objectOfClassA(filename, type); //should construct an object of class A
... //do stuff with objectOfClassA
}
File main.cpp:
int main(int argc, char** argv) {
B objectOfClassB;
objectOfClassB.foo_func("file_path", foo_func.TEXT);
}
By trying to run main program I get this error from compiler in the B.cpp file at line of function foo_func:
no match for call to ‘(A)
(std::basic_string, B::FileType&)’
which means that I'm not using the correct enum type to call A class constructor, but how can I fix this?
What am I doing wrong?
B::FileType and A::FileType are different types. You need to typedef A::FileType FileType inside B to alias the types correctly so they are interchangeable. Otherwise B::FileType is an enum which is structurally the same as A::FileType, but unrelated in the type system. This answers your primary question.
Fixing this still won't permit your code to compile, however, and this is not what the error is complaining about.
objectOfClassA is already constructed inside foo_func. Calling this->objectOfClassA(filename, type) is an attempt to use the overloaded () operator on the object; this operator does not exist so the code cannot compile. You can only construct objectOfClassA via B's constructor using initializer notation, e.g.
B::B(const std::string& filename, FileType type) : objectOfClassA(filename, type)
{
...
}
Then in main you would do this:
B objectOfClassB("file_path", B::TEXT);
Step through in the debugger to see the control flow.
Related
As an example lets say I have a class called File. Now file can be opened as binary or text. My constructor is currently File(const char*filename). Let's suppose the implementation of open is completely different binary and text. How the heck do I construct this?
I thought about using a static function but I don't want to return a pointer. I could pass in a pointer but I rather not allow a class be constructed without actually initializing it.
I was thinking about having an enum or bool in the constructor but it feels 'wrong' to me (and the way I may do this). I could have a different class name for binary and text and have both inherit a base implementation (or the other implementation) even though the only difference is the constuctor.
What's the most idiomatic way of doing this in C++?
Add a flag
enum class open_mode
{
binary,
text
};
File(const char* filename, open_mode mode);
or use a tag
struct binary_tag { };
struct text_tag { };
File(const char* filename, binary_tag);
File(const char* filename, text_tag);
Two idiomatic ways are a factory function (nothing forces you to return a pointer), or tag dispatching (which is used in the standard library, for example in std::variant).
// Factory functions
struct File {
static File openText(char const *filename);
static File openBinary(char const *filename);
};
// Tag dispatching
struct open_as_binary_t {} constexpr open_as_binary;
struct open_as_text_t {} constexpr open_as_text;
struct File {
File(char const *filename, open_as_binary_t);
File(char const *filename, open_as_text_t);
};
I could have a different class name for binary and text and have both
inherit a base implementation (or the other implementation) even
though the only difference is the constuctor.
Yes, in general, I can propose to use the polymorphism.
It is always clean, easy maintainable, extensible and understandable. Very flexible.
The best for creating something could be the factory design pattern.
Example:
class File{ protected: File(); ... }; // make constructor protected!
class BinFile : public File;
class TextFile : public File;
Then you could use it in the ordinary way:
File *f = new BinFile;
File *f = new TextFile;
Place all common stuff in class File
Implement any specific functionality per child class.
Then you could engage some factory method like:
File * OpenFile( String pathToFile, "TextFile" );
File * OpenFile( String pathToFile, "BinFile" );
In general, in this way, the code is very flexible.
Why not even simpler:
File(const char *filename,const char *mode)
{
fl=fopen(filename,mode);
//
}
And simply call with myFile = File("log.txt","rt");
I have a C++ class using Core Audio structs on OS X.
My initial implementation was like this:
class MyClass
{
private:
AUNode _converterNode;
AURenderCallbackStruct _renderCBStruct;
public:
MyClass();
~MyClass();
inline AUNode* getConverterNode() { return &_converterNode; }
inline AURenderCallbackStruct* AURenderCallbackStruct() { return &_renderCBStruct; }
};
After reading the Poco style guides, I wanted to change the order of the private/public blocks. It then looked like this:
class MyClass
{
public:
MyClass();
~MyClass();
inline AUNode* getConverterNode() { return &_converterNode; }
inline AURenderCallbackStruct* AURenderCallbackStruct() { return &_renderCBStruct; }
private:
AUNode _converterNode;
AURenderCallbackStruct _renderCBStruct;
};
The compiler now tells me that the type AURenderCallbackStruct is unknown and tells me to replace the type name with ::AURenderCallbackStruct. When I do that, there are no compiler errors.
Weirdly, this only appears for the `AURenderCallbackStruct and not the AUNode.
The AURenderCallbackStruct is defined like this:
typedef struct AURenderCallbackStruct {
AURenderCallback inputProc;
void * inputProcRefCon;
} AURenderCallbackStruct;
and AUNode is defined like this:
typedef SInt32 AUNode;
Can anyone explain why the change of order of private/public block produces a compiler error and why the error disappears when adding a ::in front of the type?
First of all it is not clear why you named the member function as AURenderCallbackStruct that coincides with the corresponding structure's name and looks like the structure constructor.
The problem is this stupid name.
in the first case the compiler thinks that you indeed define the member function that hides the corresponding name of the structure.
In the second case the compiler thinks that you trying to call the constructor of the structure.
Simply rename the function that there would not be an ambiguity.
I've been set an assignment to create an rpn calculator that takes infix notation as input. So part of it is that it has to print out different stages of the process. So first it should separate a string into tokens and then store in a vector. Then it should convert this to rpn notation (e.g 3+4 -> 3 4 +) which is the part im stuck on now the part I'm stuck on now.
I've been recommended to use virtual abstract functions for this. So first I create a class with the abstract function. Then I create a subclass which converts a string to tokens stored in a string vector, this part works fine. Then I should create another subclass which converts the input string to rpn notation, therefore I have to call the function to convert to tokens at the start of this sub-class, this is the bit which I think is going wrong.
I have been given some code as a template and so far it's been very buggy so there might be something wrong with the syntax where the error is.
So I have this as my main class
template<typename T>
class tokenstream {
public:
virtual bool process(const std::string& input, std::vector<T>& output) = 0;
};
Then this as the first subclass
class tokenifier: public tokenstream<std::string> {
public:
bool process(const std::string& input, std::vector<std::string>& output) {
//this part works fine, ive tested it.
};
So then I have to create another subclass and then call the above function inside it, this is the part where it goes wrong.
class infix2rpn: public tokenstream<std::string> {
private:
tokenifier *tokens;
public:
tokenifier(tokenstream *_tokens): tokens(_tokens) {} //I think this line is the problem
bool process(const std::string& input, std::vector<std::string>& output) {
//call the underlying tokenstream object
std::vector<std::string> infixtokens;
if(!tokens->process(input, infixtokens))
{
return false;
}
return shunting_yard(infixtokens, output);
}
bool shunting_yard(const std::vector<std::string>& input, std::vector<std::string>& output){
//i've tested the shunting_yard algorithm and it works fine
}
};
When I try to compile it I get the error "ISO C++ forbids declaration of 'tokenifier' with no type [-fpermissive].
So the part I don't understand is how to call other virtual functions from another subclass.
Thanks
Your class is called infix2rpn, so its constructor should be named infix2rpn as well, not tokenifier. This has nothing to do with virtual functions.
Moreover, your attribute should be a tokenstream<std::string>*, not a tokenifier*, because you can't convert the tokenstream<std::string>* you get in the constructor to a tokenifier*.
tokenifier(tokenstream *_tokens): tokens(_tokens) {}
This was probably meant to be constructor, but in that case, the name of the method should be infix2rpn, same as the class name.
The error means, that you specified method tokenifier that has not specified return type, only constructors and destructors have no return type.
Note that void also specification of return type, in that case it means nothing returned.
I am trying to make it possible for a programmer (who uses my library) to create nameable instances of type X that are stored inside an instance of class C (or at least are exclusive to that instance).
These are the only two (ugly) solutions I have managed to come up with (needless to say, I am just picking up C++)
1)
class C
{
public:
class XofC
{
public:
XofC() = delete;
XofC(C& mom)
{
mom.Xlist.emplace_front();
ref = Xlist.front();
}
X& access()
{
return ref;
}
private:
X& ref;
};
//etc
private:
std::forward_list<X> Xlist;
friend class XofC;
//etc
}
Problem:
Having to pass everywhere XofC instances.
2)
class C
{
public:
void newX(std::string);
X& getX(std::string);
//etc.
private:
/*possible run-time mapping implementation
std::vector<X> Xvec;
std::unordered_map<std::string, decltype(Xvec.size())> NameMap;
*/
//etc
}
Problem:
This does the job, but since all names of X (std::string) are known at compilation, the overhead of using run-time std::unordered_map<std::string, decltype(Xvec.size())> kind-of bugs me for something this simple.
Possible(?) solution: compile-time replacing of std::string with automatic index (int). Then I could use:
class C
{
public:
void newX(int); //int: unique index calculated at compile time from std::string
X& getX(int); //int: unique index calculated at compile time from std::string
//etc.
private:
std::vector<X> Xvec;
}
Questions:
Is there a 3)?
Is a compile time solution possible for 2)?
This is the real-life situation: I was starting my first C++ "project" and I thought I could use the practice and utility from an awesome user-friendly, simple and fast argument management library. I plan to make an ArgMan class which can parse the argV based on some specified switches. Switches would be named by the programmer descriptively and the trigger strings be specified (e.g. a switch named recurse could have "-r" and "-recursive" as triggers). When necessary, you should be easily able to get the setting of the switch. Implementation detail: ArgMan would have a std::unordered_map<std::string/*a trigger*/, ??/*something linking to the switch to set on*/>. This ensures an almost linear parse of argV relative to argC. How should I approach this?
You could 'abuse' non-type template arguments to get compiletime named instances:
Live on Coliru
Assume we have a data class X:
#include <string>
struct X
{
int has_some_properties;
std::string data;
};
Now, for our named instances, we define some name constants. The trick is, to give them external linkage, so we can use the address as a non-type template argument.
// define some character arrays **with external linkage**
namespace Names
{
extern const char Vanilla[] = "Vanilla";
extern const char Banana [] = "Banana";
extern const char Coconut[] = "Coconut";
extern const char Shoarma[] = "Shoarma";
}
Now, we make a NamedX wrapper that takes a const char* non-type template argument. The wrapper holds a static instance of X (the value).
// now we can "adorn" a `namedX` with the name constants (above)
template <const char* Name>
struct NamedX
{
static X value;
};
template <const char* Name> X NamedX<Name>::value;
Now you can use it like this:
int main()
{
X& vanilla = NamedX<Names::Vanilla>::value;
vanilla = { 42, "Woot!" };
return vanilla.has_some_properties;
}
Note that due to the fact that the template arguments are addresses, no actual string comparison is done. You cannot, e.g. use
X& vanilla = NamedX<"Vanilla">::value;
becuase "Vanilla" is a prvalue without external linkage. So, in fact you could do without some of the complexity and use tag structs instead: Live on Coliru
While Neil's solution did what I asked for, it was too gimmicky to use in my library. Also, sehe's trick is surely useful, but, if I understood correctly, but doesn't seem related to my question. I have decided to emulate the desired behavior using method 1), here is a less broken attempt at it:
class C
{
private:
class X
{
//std::string member;
//etc
};
public:
class XofC
{
public:
XofC(C & _mom) : mom(_mom)
{
mom.Xlist.emplace_front();
tehX = &(Xlist.front());
}
X & get(maybe)
{
if (&maybe != &mom) throw std::/*etc*/;
return &tehX;
}
private:
X * tehX;
C & mom;
};
private:
//etc
std::forward_list<X> Xlist;
friend class XofC;
//etc
};
Usage:
C foo;
bar = C::XofC(foo); //acts like an instance of X, but stored in C, but you have to use:
bar.get(foo)/*reference to the actual X*/.member = "_1_";
Of course, the downside is you have to make sure you pass bar everywhere you need it, but works decently.
This is how it looks like in my tiny argument manager library:
https://raw.github.com/vuplea/arg_manager.h/master/arg_manager.h
There are two classes defined..
class Dictionary
{
public:
Dictionary();
Dictionary(int i);
// ...
};
and
class Equation
{
static Dictionary operator_list(1);
// ...
};
but the problem is, whenever I compile this, I get a weird error message
error C2059: syntax error : 'constant'
But it compiles well when I use the default constructor on operator_list.
In C++ you cannot combine declaration and initialization. When you do not specify constructor parameters of operator_list, you do not call its default constructor: you simply declare it. You need to also initialize it in the corresponding C++ file, like this:
Equation.h
class Equation {
static Dictionary operator_list;
};
Equation.cpp:
Dictionary Equation::operator_list(1);
Note the absence of static in the CPP file: it is not there by design. The compiler already knows from the declaration that operator_list is static.
Edit: You have a choice with static constant members of integral and enumerated types: you can initialize them in the CPP file as in the example above, or you can give them a value in the header. You still need to define that member in your C++ file, but you must not give it a value at the definition time.
static Dictionary operator_list(); is a function signature declaring a function returning a Dictionary and taking no arguments, that's why your compiler let you do it.
The reasons static Dictionary operator_list(1); fails is because you can't set a value of an complex type in the declaration of your classes. You need to do this elsewhere (e.g. in the .cpp )
For more information, see this post : https://stackoverflow.com/a/3792427/103916
#include <iostream>
using namespace std;
class Dictionary
{
public:
Dictionary() {}
Dictionary(int i):page(i) {}
void display() { cout << "page is " << page << endl; }
private:
int page;
};
class Equation
{
public:
static Dictionary operator_list;
};
Dictionary Equation::operator_list(1); // static members must be initialized this way...
int main()
{
Equation::operator_list.display();
}
Output is:
page is 1