Sign in to follow this  
PumpkinPieman

How do you use "..."?

Recommended Posts

How do you go about creating and using a function with ... as a parameter? What I'm trying to do is achieve a method something a long the lines of scanf() (but different).

Share this post


Link to post
Share on other sites
You don't. Really. Please. Trust me on this. Using the ellipsis construct is a HORRIBLE idea in C++. It was kept around for C compatibility, but it breaks type safety, and means that object destruction may or may not be handled correctly. Learn from how iostreams works.

Share this post


Link to post
Share on other sites
Quote:
Original post by Sneftel
You don't. Really. Please. Trust me on this. Using the ellipsis construct is a HORRIBLE idea in C++. It was kept around for C compatibility, but it breaks type safety, and means that object destruction may or may not be handled correctly. Learn from how iostreams works.

What do you mean?

I'm going to be using this to create a method to pass arguements to a script function in C++ using AngelScript.

Share this post


Link to post
Share on other sites
Quote:
Original post by PumpkinPieman
Quote:
Original post by Sneftel
You don't. Really. Please. Trust me on this. Using the ellipsis construct is a HORRIBLE idea in C++. It was kept around for C compatibility, but it breaks type safety, and means that object destruction may or may not be handled correctly. Learn from how iostreams works.

What do you mean?


If you pass in a whole bunch of variables, you have no way of knowing what variable is of what type, and things tend to get messy. A variable of one type might be assumed to be another, which would be a Bad Thing. There are much better ways of acomplishing the same task.

Share this post


Link to post
Share on other sites
Quote:
Original post by PumpkinPieman
Alright, well. Is there some type of method besides this that will allow me to send parameters of an unknown amount?


Operator chaining works, if you don't mind altering the syntax of your calls. Take std::cout << 10 << ' ' << 30; for example. Otherwise you could pass your parameters in a std::vector<boost::any std::vector<boost::variant<int,double,std::string> > or something similar.

Share this post


Link to post
Share on other sites
What do you mean 'you don't use it' ? Use it. It's better than writing a buggy less feature complete version of the exact same thing all by yourself.

Share this post


Link to post
Share on other sites
Quote:
Original post by PumpkinPieman
I don't use the boost library, is there any other way?


Are you willing to alter your function call syntax?
Are you willing to preprocess your source code with a custom tool?

Share this post


Link to post
Share on other sites
It means "I don't use it", just like it says. I'm not going to get in to the reasons why not. I'm just trying to find alternatives to running script functions without setting the arguements one by one. (angelscript has methods that set parameters one at a time for a loaded script function)

Quote:
Original post by Fruny
Quote:
Original post by PumpkinPieman
I don't use the boost library, is there any other way?


Are you willing to alter your function call syntax?
Are you willing to preprocess your source code with a custom tool?


Well that answers my question, all I was looking for was something simple to work with. I'll try to find another method around this little problem.

Thanks for all your help.

Share this post


Link to post
Share on other sites
Quote:
Original post by PumpkinPieman
I don't use the boost library, is there any other way?


How does AngelScript expect the arguments? That'd determine how I'd solve it.

Share this post


Link to post
Share on other sites
Quote:
Original post by Way Walker
Quote:
Original post by PumpkinPieman
I don't use the boost library, is there any other way?


How does AngelScript expect the arguments? That'd determine how I'd solve it.


int SetArgDWord(asUINT arg, asDWORD value);
int SetArgQWord(asUINT arg, asQWORD value);
int SetArgFloat(asUINT arg, float value);
int SetArgDouble(asUINT arg, double value);
int SetArgAddress(asUINT arg, void *address);
int SetArgObject(asUINT arg, void *object);

arg = 0 .. n

Share this post


Link to post
Share on other sites
Quote:

This might help: Gem: A Generic Function Binding Interface


Seconded. I've implemented a system based on this paper for Lua and it is wonderful. It requires some heavier up-front effort but it pays off in the long run.

Share this post


Link to post
Share on other sites
Since I don't know how expensive context creation/destruction is, how often you'll want to make identical/similar calls, etc., this probably isn't the perfect solution for you, but it may give you an idea.


class CallASFunction {
public:
class Address {
public:
void *address;
Address(void *a = 0) : address(a) {}
};

private:
asIScriptContext *context;
unsigned int argumentCount;

public:
CallASFunction(asIScriptEngine &engine, int functionID)
: context(0), argumentCount(0) {
context = engine.CreateContext();
context->Prepare(functionID);
}
~CallASFunction() {
context->Release();
}
private:
CallASFunction(); // No touchy
CallASFunction(const CallASFunction &cf); // No touchy
CallASFunction & operator=(const CallASFunciton &cf); // No touchy

public:
friend CallASFunction & operator<<(CallASFunction &cf, asDWORD value);
friend CallASFunction & operator<<(CallASFunction &cf, asQWORD value);
friend CallASFunction & operator<<(CallASFunction &cf, float value);
friend CallASFunction & operator<<(CallASFunction &cf, double value);
friend CallASFunction & operator<<(CallASFunction &cf, void *value);
friend CallASFunction & operator<<(CallASFunction &cf, Address value);

public:
void execute(asDWORD &out) {
out = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnDWord() : 0;
}
void execute(asQWORD &out) {
out = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnQWord() : 0;
}
void execute(float &out) {
out = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnFloat() : 0;
}
void execute(double &out) {
out = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnDouble() : 0;
}
void execute(void **out) {
*out = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnObject() : 0;
}
void execute(Address &out) {
out.address = context->Execute() == asEXECUTION_FINISHED
? context->GetReturnAddress() : 0;
}
};

CallASFunction & operator<<(CallASFunction &cf, asDWORD value) {
cf.context->SetArgDWord(argumentCount, value);
++argumentCount;
}
CallASFunction & operator<<(CallASFunction &cf, asQWORD value) {
cf.context->SetArgQWord(argumentCount, value);
++argumentCount;
}
CallASFunction & operator<<(CallASFunction &cf, float value) {
cf.context->SetArgFloat(argumentCount, value);
++argumentCount;
}
CallASFunction & operator<<(CallASFunction &cf, double value) {
cf.context->SetArgDouble(argumentCount, value);
++argumentCount;
}
CallASFunction & operator<<(CallASFunction &cf, void *value) {
cf.context->SetArgObject(argumentCount, value);
++argumentCount;
}
CallASFunction & operator<<(CallASFunction &cf, Address value) {
cf.context->SetArgAddress(argumentCount, value.address);
++argumentCount;
}





CallASFunction::Address could be improved by making it act like a pointer, but I'm lazy. You might want to make CallASFunction::Object and not use void pointers directly (for consistency, it won't provide any more type safety), but I'm lazy. (Or, perhaps even better, create wrappers independent of this class that you use for those types so you don't have to convert just to call a function.) You could probably make copying and assignment feasible (context has reference counting), but I'm lazy. You should probably throw when a function doesn't return, but I'm lazy. I haven't tested it at all because I'm lazy, but you should get the idea.

Usage:
DWORD ret = 0;
CallASFunction someFunc(myEngine, someID);
someFunc << arg1 << arg2 << arg3 << CallASFunction::Address(arg4) << arg5;
someFunc.execute(ret);

[Edited by - Way Walker on April 29, 2006 8:51:59 PM]

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this