views:

238

answers:

3

Hi-- 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.

+2  A: 

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);
Pavel Minaev
A: 

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.

Barry Wark
1) Ok, but when I create the vector on the stack, how can I pass it by reference? Like, how does that _actually_ work. There I am, in my stack, blah blah blah, oh here comes a function call, lets push a new frame onto the stack, save our SP, save our locs, ok, JMP, new function...the reference points to...where? Back into the enclosing stackframe? References in C++ seem like a classic "Lets make this easier by adding more complications!" attitude. Then again, i don't actually know what they are.
Mr. Tacos
One of the main purposes of references is to allow pass-by-reference semantics without having to use pointers. Unlike a pointer, a reference is like an alias for its referent. It must be assigned at creation, cannot be null and cannot be reassigned to be a reference to a different object. I've added a link to a good introduction to my answer.
Barry Wark
Reference will indeed point to the original object, which is a variable on the upper stack frame (which is why returning a reference to a local variable in C++ is not a good idea). This isn't new to C++ - it has worked this way since "pass by reference" first appeared in the likes of Algol and Pascal, long before C++.
Pavel Minaev
A: 

If anyone from C++.com reads this thread and would like some feedback on their new product language from a novice user, here's what I got:

1) The error message of "non-class" is misleading to me. Not only is it not a class, its not an object of any kind.

2) If I follow, this is the state of affairs: Foobar foobars; //create a a foobar of T using the empty constructor Foobar foobars(); //declare a function foobars that returns a foobar of T Foobar foobars(true); //create a foobar of T, call the Foobar() Constructor that takes a bool.

That seems like a recipe for disaster, at least to my zero-experience eyes. What is the rationale here?

Mr. Tacos
I'm not sure what's "c++.com", and I'm definitely not a member of one, but still. First of all, "object" in C++ does _not_ mean "instance of a class"; rather, it's a more low-level term in the C++ object model. For example, `int` is not a class, but an `int` value is an object. As for C++ constructor syntax, it's a known pitfall - the general rule is "if it's ambiguous between local with constructor invocation, and a function definition, then parse as a function definition". The remedy in C++0x will be to use `{}` for initialization, e.g.: `FooBar foobars{}` will invoke no-arg constructor.
Pavel Minaev