Jump to content
  • Advertisement
Sign in to follow this  
Suudy

Parameter references

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm a bit lost on registering C++ functions that take parameter references. I've tried references and handles, but neither seem to work. Consider the following C++ function:
template<class T>
static
void foo(T* arg)
{
  *arg = 55;
}
Granted, this example only works for certain types of T. But I am having trouble registering this function. I've tried the following:
bool my_register(asIScriptEngine* engine)
{
  if ( engine->RegisterGlobalBehaviour(asBEHAVE_BIT_SRL, "void f(uint &out)", asFUNCTIONPR(foo<unsigned long>, (unsigned long *), void), asCALL_CDECL) < 0)
    return false;

  return true;
}
The call to RegisterGlobalBehaviour returns -10. I've looked into the code, and it fails because it says that references require a "in". So, I tried other cases:
"void f(uint &inout)"
"void f(uint @+)"
And both fail. The only call that registers successfully, but doesn't operate correctly is:
"void f(uint &in)"
And it makes sense that this doesn't work (because of the evaulation and copy semantics). I know I'm likely overlooking something simple. My search of the forums and reading the documentation hasn't revealed a solution yet. So, how do I pass a parameter to a primitive type via a pointer?

Share this post


Link to post
Share on other sites
Advertisement
The asBEHAVE_BIT_SRL (>>) operator requires two operands. Also, the script operators only allow &in references, so you shouldn't try to alter the values. The engine may in some cases send the reference to the actual variable, but in others it may be to a different variable so you may get unexpected results and difficult to find bugs, if you did what you're trying to do.

If you want to alter the value of the parameter reference, you must use a normal function that allows &out, and &inout.

The following works:


void func(int &v)
{
v = 55;
}

engine->RegisterGlobalFunction("void func(&out)" asFUNCTION(func), asCALL_CDECL);

Share this post


Link to post
Share on other sites
Quote:
Original post by WitchLord
The asBEHAVE_BIT_SRL (>>) operator requires two operands.

The above was a contrived example. I'm actually trying to get the input streams ported to the latest Angelscript version.
Quote:
Original post by WitchLoard
Also, the script operators only allow &in references, so you shouldn't try to alter the values. The engine may in some cases send the reference to the actual variable, but in others it may be to a different variable so you may get unexpected results and difficult to find bugs, if you did what you're trying to do.

Indeed. So how do input streams work? The streams code is based on an older version of the Angelscript library, and in it I see the following:

template <class T>
std::istream * ExtractOperator(std::istream * in, T * value)
{
*in >> *value;
return in;
}

coupled with

RegisterBehavoir(engine, asBEHAVE_BIT_SRL, "instream & f(instream &, bool &)", ExtractOperator<bool>);

and the RegisterBehavoir() function is defined as:

template <class T>
inline void RegisterBehavoir(asIScriptEngine * engine, asDWORD behaviour, const char * name, T func)
{
engine->RegisterObjectBehaviour(0, behaviour, name, asFunctionPtr(reinterpret_cast<void (*)()>(func)), asCALL_CDECL);
}

So if the SRL operator only allows &in references, then how did the above code work? How can I register an input stream class and use the SRL operator as an extraction operator if I can only have &in references?

Share this post


Link to post
Share on other sites
I wrote this long answer trying to give you a solution, but when I finished I realized that I had completely missed the point of the true problem. I was focusing on the actual stream object, but forgot about the value that is extracted from the stream.

There is really no easy solution to this problem at the moment. Since only &in references are allowed, there is no way you can have the operator change the value of the operands unless the operands use shared memory.

I need to change the way the library handles this. The library must be able to allow operators change the value of the operands for this to work.

I'll finish version 2.4.0 first, and after that I'll give this problem top priority. I was planning on changing the way parameter references work anyway, since I'm not quite satisfied with the current solution.

I hope that I will be able to find a solution to this. But I not 100% sure that it is possible, without breaking other restrictions that are needed to keep the library safe.

Share this post


Link to post
Share on other sites
Could the stream be written to take a handle? It would then be possible for AngelScript to automatically create a handle to stack-based object and pass that to the function. Some sort of binding flag would have to be added to allow this conversion on specific functions, or the script could do the conversion-to-handle explicitly. Allowing it universally would probably cause problems.

Share this post


Link to post
Share on other sites
This is a really a rather difficult problem that Suudy discovered.

Some of the problems that I'm facing:

1. I cannot keep pointers on the stack while evaluating expressions. It's possible that they become invalid before they are used again.

2. Argument expressions for output references are evaluated after the function call, because of number 1. A returned reference, for example, must be used before the output parameters are evaluated.

3. I must keep operator precedence and order of evaluation, e.g. for >> the left operand must be evaluated before the right operand. This goes against rule number 2, if I allow output references for operators.

Allowing object handles doesn't solve this, although it might help in some situations. Primitives for example cannot use object handles, and somehow wrapping them in an object that support handles isn't really a good solution. For example, how would I wrap an object property of a primitive type, or an element in an array?

Share this post


Link to post
Share on other sites
I understand why the << operator can only accept in references, but I'm forced to wonder why the >> operator doesn't then only accept out references.

Quote:
the script operators only allow &in references


Is this true for all operators? It would make sense if it were. Operator >> for streams is unigue in that it is the only operator that modifies it's right-hand side. Could it be a special case that is required to be registered with an out reference?

Share this post


Link to post
Share on other sites
We decided on a workaround for the output parameter references. Rather than rely on the SRL operator, we just defined a template member function overloaded for all the types we are interested. We just don't get the pretty chaining.

For example, we defined:

template<class T>
bool mystream::get(T* val)
{
_stream >> *val;
}

Where _stream is the wrapped input stream. We registered them as overloaded functions, one for each type:

engine->RegisterObjectMethod("ifstream", "bool get(bool &out)", asMETHODPR(asCIScriptStream, get<bool>, (bool*), bool), asCALL_THISCALL);
engine->RegisterObjectMethod("ifstream", "bool get(uint &out)", asMETHODPR(asCIScriptStream, get<unsigned long>, (unsigned long*), bool), asCALL_THISCALL);

etc, etc, for each type we want.

This works fine for now, and in the end, we will likely just add the extraction operator rather than remove these functions.

Thanks for generating and supporting such a fantastic piece of software! I can't say enough about how much we appreciate what you've done. Our end-users love the ability to script their testbenchs, and with the huge variety of add-ons (the preprocessor being our favorite!), we are all very thrilled.

Share this post


Link to post
Share on other sites
Suudy:

I'm happy that you found a solution, even though it may not be exactly what you had in mind.

I'm also very happy that you enjoy the library so much. Please spread the word. [wink]

Deyja:

Quote:
Original post by Deyja
I understand why the << operator can only accept in references, but I'm forced to wonder why the >> operator doesn't then only accept out references.

Quote:
the script operators only allow &in references


Is this true for all operators? It would make sense if it were. Operator >> for streams is unigue in that it is the only operator that modifies it's right-hand side. Could it be a special case that is required to be registered with an out reference?


The problem is that all operators only support &in. To AngelScript there is no difference between any of the overloaded operators, except their token and the precedence, e.g. << and >> is treated the exact same way. If I allow >> to be registered with an &out operands, I should allow all operators to do that. I won't make a special case just to support streams.

None of the default operators modify the operands (this is true for C++ as well). I'm also not too fond of the C++ streams. This is why I forgot about the possibility that someone would want to register operators that change the value of the operands.

Maybe I can solve this case by implementing member operators. The left hand operand would then by default be changeable, and I would just have to worry about the right hand operand. I'll have to think about this some more.

Share this post


Link to post
Share on other sites
Wouldn't the left hand side need to be changable already, to support ++ and += (etc)?

I understand why you don't want to make a special case. I hate them too. :D

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!