(Obj) C++: Instantiate (reference to) class from template, access its members? - c++

I'm trying to fix something in some Objective C++ (?!) code. I don't know either of those languages, or any of the relevant APIs or the codebase, so I'm getting stymied left and right.
Say I have:
Vector<char, sizeof 'a'>& sourceData();
sourceData->append('f');
When i try to compile that, I get:
error: request for member 'append' in 'WebCore::sourceData', which is of non-class type 'WTF::Vector<char, 1ul >& ()();
In this case, Vector is WTF::Vector (from WebKit or KDE or something), not STD::Vector. append() very much is supposed to be a member of class generated from this template, as seen in this documentation. It's a Vector. It takes the type the template is templated on.
Now, because I never write programs in Real Man's programming languages, I'm hella confused about the notations for references and pointers and dereferences and where we need them.
I ultimately want a Vector reference, because I want to pass it to another function with the signature:
void foobar(const Vector<char>& in, Vector<char>& out)
I'm guessing the const in the foobar() sig is something I can ignore, meaning 'dont worry, this won't be mangled if you pass it in here'.
I've also tried using .append rather than -> because isn't one of the things of C++ references that you can treat them more like they aren't pointers? Either way, its the same error.
I can't quite follow the error message: it makes it sound like sourceData is of type WTF:Vector<char, 1ul>&, which is what I want. It also looks from the those docs of WTF::Vector that when you make a Vector of something, you get an .append(). But I'm not familiar with templates, either, so I can't really tell i I'm reading that right.
EDIT:
(This is a long followup to Pavel Minaev)
WOW THANKS PROBLEM SOLVED!
I was actually just writing an edit to this post that I semi-figured out your first point after coming across a reference on the web that that line tells the compiler your forward declaring a func called sourceData() that takes no params and returns a Vector of chars. so a "non-class type" in this case means a type that is not an instance of a class. I interpreted that as meaning that the type was not a 'klass', i.e. the type of thing you would expect you could call like .addMethod(functionPointer).
Thanks though! Doing what you suggest makes this work I think. Somehow, I'd gotten it into my head (idk from where) that because the func sig was vector&, I needed to declare those as &'s. Like a stack vs. heap pass issue.
Anyway, that was my REAL problem, because I tried what you'd suggested about but that doesn't initialize the reference. You need to explicitly call the constructor, but then when I put anything in the constructor's args to disambiguate from being a forward decl, it failed with some other error about 'temporary's.
So in a sense, I still don't understand what is going on here fully, but I thank you heartily for fixing my problem. if anyone wants to supply some additional elucidation for the benefit of me and future google people, that would be great.

This:
Vector<char, sizeof 'a'>& sourceData();
has declared a global function which takes no arguments and returns a reference to Vector. The name sourceData is therefore of function type. When you try to access a member of that, it rightfully complains that it's not a class/struct/union, and operator-> is simply inapplicable.
To create an object instead, you should omit the parentheses (they are only required when you have any arguments to pass to the constructor, and must be omitted if there are none):
Vector<char, sizeof 'a'> sourceData;
Then you can call append:
sourceData.append('f');
Note that dot is used rather than -> because you have an object, not a pointer to object.
You do not need to do anything special to pass sourceData to a function that wants a Vector&. Just pass the variable - it will be passed by reference automatically:
foobar(sourceData, targetData);

Dipping your toes in C++ is never much fun. In this case, you've run into a couple of classic mistakes. First, you want to create an instance of Vector on the stack. In this case the empty () is interpreted instead as a declaratiton of a function called sourceData that takes no agruments and returns a reference to a Vector. The compiler is complaining that the resulting function is not a class (it's not). To create an instance of Vector instead, declare the instance without the () and remove the &. The parentheses are only required if you are passing arguments to the instance constructor and must be omitted if there are no arguments.
You want
Vector<char, sizeof 'a'> sourceData;
sourceData.append('f');
Vector<char, sizeof 'a'> outData; //if outData is not instantiated already
foobar(sourceData, outData);
This Wikipedia article gives a decent introduction to C++ references.

Related

Error with std::bind and templated member functions

I am currently writing a gameboy emulator for practicing C++. I have gotten to the part where I implement CPU instructions and decided a vector of std::function was a good choice.
Please note: u8 is an alias for uint8_t.
In my code, there is a vector of std::function<u8()> with three types of members:
A lambda expression that returns u8.
Pointer to a member function.
Pointer to a templated member function.
I tried to use an initalizer list at first, but it didn't work. I later found out that is because I needed a call to std::bind(/*function ptr*/, this); on the pointers, but when calling this on the templated function pointers, I get the following error: no matching function for call to 'bind'. I would like to have an initalizer list, as right now it is a function with successive calls to emplace_back.
Here is the erroring line:
instruction_set.emplace_back(bind(&CPU::OPLoadDualRegister8<B, B>, this)); // 0x40 LD B, B
One interesting thing is that when B is replaced with a literal (e.g. 0x00) it works perfectly. B is a u8 and that is what the template accepts.
So:
Is there any way I can do this less convoluted? (e.g. init lists, std::function with member function ptrs, etc.)
If this is the best way, what do I do about the templated ptrs?
Would it better if I took the template params as args and used std::bind to resolve them (all params are either u8 or u8&.
Any optimization suggestions?
Thanks, Zach.
Okay, there is a lot going on here between your question and the comments. Here are some things I notice right off the bat:
If you are going to index into a vector to decode op codes, you probably shouldn't just emplace_back into the vector in order. Instead grow the vector to its final size, filling it with null values and use the subscript operator to put the functions in. instruction_set[0x40] = ...
Using a switch statement and just calling the functions directly is likely a way better choice. Obviously, don't know the ins and outs of your project, so this may not be possible.
When you say B is u8 do you mean B is variable of type u8? Plain 'ol variables can't be used to instantiate templates. B would have to be a macro, template parameter on the calling function, constexpr variable, or static const (basically known at compile time).
std::bind is never any fun for anyone to use, so you are not alone. I don't think it is the root cause of your issue here, but you should probably prefer binding things using capturing lambdas.
Funnily enough C++'s new hearthrob Matt Godbolt (author of Compiler Explorer) gave a talk on emulating a 6502 in JavaScript last year. It's not exactly an authoritative reference on the subject, but it may be worth a watch if you are interested in emulating old microprocessors.

class forward declaration

Can I use forward declaration for a class in order to put it's definition and Implementation later in the program after it's been used (similar to what is done about functions)?
(I need to join multiple source files of a program into a file, and i want to put the classes' definitions and Implementations at the end of the file in order to main be at the top of the file.)
Yes you can, to a certain extent.
You have to realize that the C++ compiler is quite stupid, and doesn't read ahead. This is the reason why you have to use function prototypes (among some other reasons).
Now, a function isn't hard for compiler to resolve. It just looks at the return type of the function, and the types of the parameters of the function, and just assumes that the function is there, without any knowledge about what's actually inside the function, because it ultimately doesn't matter at that point.
However, the contents of the class do matter (the compiler needs to know the size of the class for example). But remember about the not reading ahead bit? When you forward define a class, the compiler doesn't know about what's in it, and therefore is missing a lot of information about it. How much space does is need to reserve for example?
Therefore, you can forward define classes, but you can't use them as value types. The only thing you can do with it (before it has been concretely declared), is use pointers to it (and use it as a function return type and template argument, as pointer out by
#Cheersandhth.-Alf).
If the thing you need to use isn't a pointer, you should probably use headers (read this if you want to learn more about that).
Without a class definition somewhere earlier, you can't use any class members, nor can you create any instances, but you can
use T* and T& types,
use T for formal return type and parameter declarations (yes even by value),
use T as a template parameter,
and possibly more, but the above is what occurred to me immediately.
So if that's all you need, then you're set to go with the forward-declarations.
However, all that the forward declaring buys you in the sketched situation is added work, maintaining the same code in two places, so it's difficult to see the point of it…
Oh, I just remembered, there is a particularly nasty Undefined Behavior associated with forward-declared incomplete types, namely using delete p where p is a pointer to incomplete type. This requires the destructor to be trivial. If the compiler is good then it warns, but don't count on it.
In summary, I would just place main at the very end of that code, where it belongs, avoiding all the problems.

Disabling "bad function cast" warning

I'm receiving the following warning:
warning: converting from 'void (MyClass::*)(byte)' to 'void (*)(byte)'
This is because I need to pass as argument a member function instead of an ordinary function. But the program is running correctly.
I'd like to disable this warning (Wno-bad-function-cast doesn't work for C++) or to implement a different way to pass a member function.
No. Take this warning seriously. You should rather change your code to handle this scenario.
Pointer to member function(void (MyClass::*)(byte)) and normal function pointer (void (*)(byte)) are entirely different. See this link. You cannot cast them just like that. It results in undefined behavior or crash.
See here, how they are different:
void foo (byte); // normal function
struct MyClass {
void foo (byte); // member function
}
Now you may feel that, foo(byte) and MyClass::foo(byte) have same signature, then why their function pointers are NOT same. It's because, MyClass::foo(byte) is internally resolved somewhat as,
void foo(MyClass* const this, byte);
Now you can smell the difference between them.
Declare pointer to member function as,
void (MyClass::*ptr)(byte) = &MyClass::foo;
You have to use this ptr with the object of MyClass, such as:
MyClass obj;
obj.*ptr('a');
You can't pass a function that takes two arguments to a place that expects a function that takes one. Can't be done, forget about it, period, end of story. The caller passes one argument to your function. It doesn't know about the second argument, it doesn't pass it to your function, you can't make it do what you want however hard you try.
For the very same reason you can't pass a non-static member function where a regular function is expected. A member function needs an object to operate on. Whatever code calls your function doesn't know about the object, there's no way to pass it the object, and there's no way to make it use the right calling sequence that takes the object into account.
Interfaces that take user's functions, without taking additional data that the user might want to pass to his function, are inherently evil. Look at the qsort() function from the C standard library. That's an example of an evil interface. Suppose you want to sort an array of string according to some collation scheme defined externally. But all it accepts is a comparison function that takes two values. How do you pass that collation scheme to your comparison function? You can't, and so if you want it working, you must use an evil global variable, with all the strings attached to it.
That's why C++ has moved away from passing function pointers around, and towards function objects. Function objects can encapsulate whatever data you want.
Also, this may be helpful
union FuncPtr
{
void (* func)(MyClass* ptr, byte);
void (MyClass::* mem_func)(byte);
};

What is wrong with my syntax in this 1 line bit of code (pointers and references and dereferences oh my)?

The code that I am having trouble with is this line:
result.addElement(&(*(setArray[i]) + *(rhs.setArray[j])));
The + operator in my class is overloaded like this (there are a variety of overloads that can fit in this set, but they all have a similar header):
const Rational Rational::operator+(const Rational &rhs) const
The setarrays in the code above are both arrays of pointers, but the + operator requires references, which might be the problem.
AddElement, the method of result, has this header:
bool Set::addElement(Multinumber* newElement)
The Multinumber* in the header is the parent class of Rational, mentioned above. I don't think any of the specific code matters. I'm pretty sure that it is a syntax issue.
My compiler error is:
68: error: invalid conversion from 'const Multinumber*' to 'Multinumber*'
Thank you for your help!
the issue is with const
bool Set::addElement(Multinumber* newElement) should be Set::addElement(const Multinumber* newElement)
Your operator + returns a const object. However, addElement requires a non-const object, which is where your compiler error is coming from. Basically, addElement is telling you that it feels at liberty to modify your Multinumber at will, but the operator + is beginning you not to modify the returned value.
You should just return a non-const object, unless there's a good reason not to. You're not returning a reference after all.
Of course, if the data in your Set is supposed to be constant and will never be changed, you may as well make addElement take a const pointer, and make sure that it internally deals with const pointers EVERYWHERE.
The issue is with the addElement expecting a non-const where as operator+ is returning a const object.
The fix for the code is cast the return as mentioned below
addElement((Multinumber * )&( *(setArray[i]) + *(rhs.setArray[j])));
If you dont want to cast, as casting might defeat the purpose of type checking here, then you have to change the signature of the addElement. That depending upon your project scope may have impact else where and if this API is public and other developers are using it. Changing signature will impact them also.
So choose wisely.
This code has much more serious issues than you can fix by adding a const or a typecast somewhere.
The result of this code will ultimately be a crash somewhere down the line, because you're passing a pointer to a temporary. Once you finish with line of code that calls addElement, the pointer will be left dangling, and trying to use the object it points to will either result in nonsense (if you're reading the object) or stack corrpution (if you're writing to the object).
The best way to redefine your code would be to change this to
bool Set::addElement(Multinumber newElement) //pass the Multinumber by value
and call addElement as follows:
result.addElement(*setArray[i] + *rhs.setArray[j]);
Note that I eliminated all of the extra parentheses because * has lower precedence than [], so the parentheses around setArray[i] and setArray[i] were redundant. I think the code is more readable this way.
Well really, if I can guess what's going on here, setArray is the internal storage of the Set class, so it's type will need to be redefined from Multinumber** to Multinumber*, in which case the call really should be
result.addElement(setArray[i] + rhs.setArray[j]);
EDIT Ugggh. None of the above will actually allow you to keep your polymorphism. You need to call new Rational somewhere, and the only reasonable place that I can think of is:
result.addElement( new Rational(*setArray[i] + *rhs.setArray[j]) );
This will work without having to redefine Set::addElement.
A better solution would be to redesign the whole thing so that it doesn't depend on polymorphism for numeric classes (because numeric classes really shouldn't be wrapped in pointers in most normal use).

Accessing a Pointer to a pointer in C++

Hi I am using a 3rd party library in my iPhone application that uses C++ one of the methods i need to use returns a pointer to a pointer of a class. like follows.
DLL classAttributes** getAttributes();
I can successfully call the method and return the value into a pointer to a pointer like so;
classAttributes **attributes = cPPClass->getAttributes();
however i can't seem to access any of the methods on the class for example i know that the class has a function called getName(); but when i try calling it i get errors.
attributes->getName(); 'Request for member 'getName' in *attributes'; which is of non-class type 'attributes*''
I did some googling and found some stuff that said to access a pointer pointer address use the format
&(*attributes)->getName(); 'invalid uses of incomplete type 'struct attributes'
Any help would be much appreciated.
Thanks.
'invalid uses of incomplete type 'struct attributes' indicates that you need to #include the header file for it. It's only forward-declared at this point in your code.
What you probably want is a classAttributes*. Since you have a classAttribues** , you want to dereference it once to get to the classAttributes*.
(*attributes)
From there you can probably call the members of the class.
classAttributes **attributesArray = cPPClass->getAttributes();
classAttributes *attributesObject(*attributesArray);
attributesObject->getName();
First consider what you would do if the function returned a pointer to a classAttributes variable. In this case, you would simply do:
attributes->getName();
Since it's a pointer to a pointer, you must first dereference it and then use the -> operator:
(*attributes)->getName();
If this doesn't work, it may be a problem caused by the function not being implemented or by inheritance.
Without knowing more about the library, it's hard to say. But it could be returning an array of items:
attributes[0]->getName();
attributes[1]->getName();
The questionable part about my guess, though, is that there is no obvious way to know how many items there are.
By the looks of it, you'd probably have to do is this way (i.e. no ampersand):
(*attributes)->getName();
This is because dereferencing it once will give you a pointer to a struct, on which you can then use the -> operator. What's happening when you do &(*attributes) is that you're dereferencing the pointer, then getting the address of the object you have — in effect making it a no-op.