# '...' in C++.

This topic is 4408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

int printf(const char *buffer, ...); // Question.


How do you make use of the '...' in functions? Printf uses it... Any websites with info? Thanks!

##### Share on other sites
In this particular example, the ellipsis means there are optional, follow-on arguments that can be passed.

##### Share on other sites
You don't, because "..." is not C++. Using the dread ellipses construct "..." in C++ is punishable by death or just a beating handed to you by Fruny or Zahlman. If you want something like that you'll probably have to use streams.

##### Share on other sites
Quote:
 How do you make use of the '...' in functions? Printf uses it...

you try not to. this construct is rarley seen in c++.

but look up this, if you want to

##### Share on other sites
To be a little more informative: A function declared this way is called a "variadic" function. To make them work you need to do some work with some rather nasty macros (although it's not a very complicated process). Basically what happens is that all the things in that are passed get tossed onto the stack in order, regardless of their types or sizes, and it's up to the function to figure out how many things are there and what their types and sizes are. Since there isn't a reasonable way to do this in general, usually what these functions do is accept some information in the first argument (such as a printf-style 'format string') that is then interpreted to figure out what needs to go on.

As I'm sure you can imagine, this is tricky to get right, and it also can cause all kinds of undefined behaviour if the format string doesn't properly match the provided data (not to mention the annoyance of having to put it in in the first place, for those functions that *don't* format a string but just want extra arguments). It also just plain doesn't work with lots of C++ types - basically anything that isn't a POD type, because copy constructors aren't going to be invoked properly. Good luck dealing with references, too.

So yeah, as a rule of thumb, just don't freakin' do it, or even think about it. Set up some kind of streaming interface instead. If you do need printf-style formatted I/O (e.g. because you need "compound strings" for localization, where the order of outputted things might vary by language, and you don't want to have to recompile/change code to support it), you should take a look at boost::format.

##### Share on other sites
This seems relevant (as found in several signatures):

"Basically whenever you invoke the dread ellipses construct you leave the happy world of type safety." -- SiCrane

It should not be used in c++, and only very carefully in c.

##### Share on other sites

Now, if you are still really curious, here's an example:

void logMessage( const char* szMessage, ... )
{
static I8 szBuffer[4097];
va_list list;
va_start( list, szMessage );
vsprintf( szBuffer, szMessage, list );

if (LogManager::InstancePtr())
LogManager::Instance().logMessage (szBuffer);

va_end( list );
}

##### Share on other sites
Now now, the ellipses construct does have a place; so does goto. You just don't want to use it unless you're really, really sure you need it. In short, someone posting in 'For Beginners' with a question of the form 'How do you...?' is probably a good candidate for passing a linked list instead. :)

##### Share on other sites
Quote:
 Original post by King of MenNow now, the ellipses construct does have a place; so does goto. You just don't want to use it unless you're really, really sure you need it. In short, someone posting in 'For Beginners' with a question of the form 'How do you...?' is probably a good candidate for passing a linked list instead. :)

Huh?

Oh no no no, I'm not a beginner, definately not.

I have a templated doubly linked list with id's and iterators, and it's pretty good :).

Then, I have SDL/OpenGL graphics classes to handle sprites, text, stuff. I have an egine class, and event class, and so much more.

##### Share on other sites
I just love being able to contribute to a thread without ever having posted in it. However...
Quote:
 Original post by ZahlmanIt also just plain doesn't work with lots of C++ types - basically anything that isn't a POD type, because copy constructors aren't going to be invoked properly.

Actually, what happens on most compilers is the the copy construction of the argument proceeds correctly. It's just that the destructor isn't called. So not only are you leaving the happy world of type safety, you also have a potential memory leak every time you call a function with the ellipses construct, because you may have accidently passed a class type to it. Though I have noticed on one occassion, that had horrible function pointer typecasting involved, the opposite happening: the copy constructor wasn't called and the destructor was called. However, I'm not sure that the ellipses had anything to do with that, since the code was basically a walking undefined behavior.

##### Share on other sites
Quote:
 Original post by agi_shiOh no no no, I'm not a beginner, definately not.

You posted in For Beginners, did you not?

##### Share on other sites
Someone mentioned the "use a linked list" statement above, and I want to reiterate that ...

And in Standard C++ idioms, use an iterator range ...

Just like the standard algorithm functions do. Then you can work in any situation in which they have a proper C++ style container ...

Sure it still doesn't let you do stuff like you can in .NET with an automatically built "params" array. But it gets you 90% of the way there, with almost no pain.

##### Share on other sites
Quote:
 Original post by Anonymous PosterYou don't, because "..." is not C++.

You've overstated to the point of misinformation without disclaimer or clarification. Bad AP.

OP: They're a bad way to create variable-argument functions, this is a reminant of C best avoided - they're basically a big can of "undefined". They enforce no type safety, do not work with objects (any "working" examples are invoking undefined behavior and are not guaranteed to work on other compilers, nevermind other platforms), and are basically evil. Although legal in C++, one of the few things I'd include in any "Best Practices" guide would be to not use them, except prehaps with SFINAE concepts.

Better Alternatives to using Elipsis:
* Containers [ google "Standard C++ Library" ]
* Operator Chaining [ google "C++ Operator Chaining" ]

Better Alternatives to printf:
* Iostreams [ google "Standard C++ Library" ]
* Boost.Format [ navigate http://www.boost/org/ ]

##### Share on other sites
Quote:
 Huh?Oh no no no, I'm not a beginner, definately not.I have a templated doubly linked list with id's and iterators, and it's pretty good :).Then, I have SDL/OpenGL graphics classes to handle sprites, text, stuff. I have an egine class, and event class, and so much more.

If your not a beginner (and Im sure you are not), you should be aware that mentioning ... and C++ in the same post will piss of SiCrane and Zahlman to the brink of madness.

##### Share on other sites
A small question: has anyone got any examples/cases where varargs functions are useful except printf style functions? (and cases where regular method chaining wouldn't work). I'm not being sarcastic, I'd honestly like to know.

##### Share on other sites
Quote:
 Original post by OrangyTangA small question: has anyone got any examples/cases where varargs functions are useful except printf style functions? (and cases where regular method chaining wouldn't work). I'm not being sarcastic, I'd honestly like to know.

Sure.
For example, I've got a base class Base_Msg, all other classes need to derive from it to form a communication web between unrelated objects of different classes:
class Base_Msg{public:    void ProcessMessage (MessageType const Msg, ...) ;private:    virtual void DoProcessMessage (MessageType const Msg, ...) ;} ;

The Msg is an enumeration of type MessageType, how the message will be processed and the amount of arguments need to be passed depends on the message itself.

A little more detailed: In an arbitrary object of type Player that is managed by an object of type PlayerPool, I need a way to notice the parent PlayerPool when the Player is about to die. I may declare them like this:
class PlayerPool : public Base_Msg{public:private:    void DoProcessMessage (MessageType const Msg, ...) ;} ;class Player //No need to derive Basg_Msg here{public:    //Constructor        explicit Player (Base_Msg *const pOwner) ;private:    //Member variables        Base_Msg *m_pOwner ; //This is a pointer to the owner of the class} ;

Can you see the benefit ?. My object can get any information from any other unrelated objects at anytime without the headaches of forward declaration (sometime you just can't forward declare to make them work).

But I use the additional arguments sparingly, most of the time my MessageType enum has single-argument message only. It promotes some useful uses of virtual arguments though.

##### Share on other sites
Uh. No. Not being able to figure out how to use include files properly is a pretty bad reason to use variadic functions. Your code has left the happy world of type safety for no appreciable reason.

##### Share on other sites
You're right, I said that I use them sparingly. But there are some situations this is one of the very few viable solutions: The parent and the child objects both need to know about each other in my example.

Basically Windows uses the same technique to transfer messages to and from windows in the system, but it is restricted to have two additional arguments. If a window needs more information, the caller has to build a struct to pass it along with the message.

So, one possible alternative is to declare a number of virtual DoProcessMessage () functions that take two (or possibly three) additional arguments. This has the same advantages of freely communicating between objects and has no disadvantages of losing type-safety.

##### Share on other sites
Although it _IS_ C and not C++, the CPython API uses vargs for parsing parameters out of a function call (when calling C from Python). For example (randomly from my engine Python binds),

PyArg_ParseTuple(args, "sifii:_Menu.MessageBox", &msg, &mbType, &timeout,                             &timeoutAction, &eventListener)

I do however prefer using printf style formatting for error logging, but I'm somewhat pushing towards replacing it with some kind of streaming system (forgetting to use .c_str() when logging a std::string value makes things go boom...done that too many times -_-).

I'll have to look into boost::format to see if I can possible use/borrow that :).

##### Share on other sites
Quote:
 Original post by Skeleton_V@TBasically Windows uses the same technique to transfer messages to and from windows in the system, but it is restricted to have two additional arguments. If a window needs more information, the caller has to build a struct to pass it along with the message.So, one possible alternative is to declare a number of virtual DoProcessMessage () functions that take two (or possibly three) additional arguments. This has the same advantages of freely communicating between objects and has no disadvantages of losing type-safety.

Or you could wrap your MessageType variable up in a Message class from which all message types are derived, so that you only ever pass a single Message* to DoProcessMessage. Derived types then contain all the data one wishes to attach to the message. DoProcessMessage would then look like this:

void MyObject::DoProcessMessage (const Message* Msg){ switch(Msg->TypeCode) {  case MSG_TYPEONE:   const TypeOneMessage* typeOneMsg = static_cast<const TypeOneMessage*>(Msg);   /* ... do stuff with typeOneMsg ... */   break;  case MSG_TYPETWO:   const TypeTwoMessage* typeTwoMsg = static_cast<const TypeTwoMessage*>(Msg);   /* ... do stuff with typeTwoMsg ... */   break; }}

(Suffice it to say that if you were working for me and I saw you writing code like what you've presented here, you wouldn't be working for me for very long).

##### Share on other sites
Quote:
 Original post by Skeleton_V@TYou're right, I said that I use them sparingly. But there are some situations this is one of the very few viable solutions: The parent and the child objects both need to know about each other in my example.

So? You still don't need to use variadic functions to handle that dependency. Your "solution" also obscures intent. You say your parent and child classes need to know about each other, but what information they need from each other enters the black abyss of the ellipses. Remember source code isn't just written to get the computer to do what it wants, source code should also be written to express intent to other human beings.

Quote:
 Basically Windows uses the same technique to transfer messages to and from windows in the system, but it is restricted to have two additional arguments. If a window needs more information, the caller has to build a struct to pass it along with the message.

And you will notice that the Windows API is a C API, not a C++ API. Many of the necessary hacks in C should not be translated to C++ application since C++ presents a richer set of semantics to express intent.

##### Share on other sites
Quote:
 static_cast(Msg);

You meant dynamic_cast<>, didn't you ?.

Although your approach doesn't really fulfill type-safety, it is inherently better than mine :). I believe you don't mind lending me your idea ?. Thanks for the suggestion.

: I see, thanks SiCrane.

##### Share on other sites
He means static_cast because the exact type is "known" as a result of the type code in this system. Needless to say, this is fragile and rather silly, because it amounts to implementing your own RTTI - for a situation where polymorphism ought to do the trick:

void MyObject::DoProcessMessage (const Message* Msg) {  // for example. Assuming a virtual function  Msg->doProcessingThatCaresAbout(*this);}

You might want to read this.

##### Share on other sites
Aye, double dispatch is an alternative - though I don't much like Zahlman's solution as it makes message-handling behavior part of the message class instead of part of the message-handling object, so if you want to send a message that will change a handler's internal state, the message will need to be a friend of the message-handler. General-purpose messages would end up needed to know about (and access) an awfully large number of different agents.

Typecodes will also become necessary when you want to send messages over the network.

If you really want to perform a double dispatch, I'd do something like this:

class BaseMessageHandler{ public: void HandleBaseMessage(const BaseMsg* msg); virtual void HandleMessage(const TypeOneMsg* msg) {assert(false && "TypeOne message not handled");} virtual void HandleMessage(const TypeTwoMsg* msg) {assert(false && "TypeTwo message not handled");} /* ... etc for all message types ... */};void BaseMessageHandler::HandleBaseMessage(const BaseMsg* msg){ switch(msg->typecode) {  case MSG_TYPEONE: HandleMessage(static_cast<const TypeOneMsg*>(msg)); return;  case MSG_TYPETWO: HandleMessage(static_cast<const TypeTwoMsg*>(msg)); return;  /* .. etc for all message types ... */ };}

That way, individual concrete message handlers can override the HandleMessage() function for each of the message types they are interested in, and messages with known types can be sent directly by calling HandleMessage (if coming from a local source) instead of HandleBaseMessage.

I use static_cast because the type is known, as Zahlman says.

##### Share on other sites
Quote:
 Original post by cow_in_the_wellI do however prefer using printf style formatting for error logging, but I'm somewhat pushing towards replacing it with some kind of streaming system (forgetting to use .c_str() when logging a std::string value makes things go boom...done that too many times -_-).

Doesn't your compiler have a switch to type-check arguments to printf/scanf ???
My compiler (GCC, Apple's variant) doesn't turn this on by default, but it comes in handy.