# a mechanism to fill in for templated overloads

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

## Recommended Posts

I have a problem with encapsulation/scope management. In particular, this is a rough outline of the relevant code (typo warning - I writing this up in my browser. That being said, my question has nothing to do with syntax, but rather the overall logic and the limitations of C++):


// forward declare the problem type, as both scriptengine and luaengine need to have it exactly same (eg can't even do this in-line)
struct IActor;

class scriptengine {
protected:
// main argument sink
template <typename T, typename ...Args>
void push_arg(IN T arg, IN Args ...args)
{ push_arg(arg); push_arg(args...); }

// PROBLEM LIES HERE: IActor is implementation-specific; do not want knowledge of this in the base class!
virtual boolean push_arg(IN const IActor* arg) = 0;

// force specialization of a few basic types, though
virtual boolean push_arg(IN const char* arg) = 0;
virtual boolean push_arg(IN real arg) = 0;
virtual boolean push_arg(IN int32 arg) = 0;
// terminate recursion
virtual boolean push_arg();

};

class luaengine
: public scriptengine {

public:
// having this here is sorta-kinda okay - I can simply specialize the overload to handle
// implementation-specific types as needed
virtual boolean push_arg(const IActor* arg) { ... }

// provide implementations and other blah
virtual boolean push_arg(const char* arg) { ... }
virtual boolean push_arg(real arg) { ... }
virtual boolean push_arg(int32 arg) { ... }

};


Basically in the above sample I want the argument sink to forward any types that are not directly recognized by scriptengine to specializations of push_arg in luaengine  without having any knowledge of the overloaded class or what types it supports. Things that don't work include the usual expected stuff:

• a void* proxy
• providing a separate implementation of the argument sink in the overloaded class

Is there anything else I might be missing? I want scriptengine to be autonomous and work without any knowledge of types other than a couple of basic types. That said the main benefit right now is compile time. And, you know, principle  :ph34r: .

Edited by irreversible

##### Share on other sites

Okay, here's one way to do it. I'm guessing it's not the most elegant method, but it does work. In short, the idea is to get rid of push_arg() specialization inside member functions and set up a layer of indirection to pass the arguments to the correct overload. I reckon a snipped will be more illustrative.

scriptengine_base.h

// forward declare an abstact type translator
template <typename T>
void push_arg(IN T arg, IN scriptengine* eng);

class scriptengine {
protected:
// do as before, but this time push_arg() member functions are missing, so the compiler will look at globals
template <typename T, typename ...Args>
void push_arg(IN T arg, IN Args ...args)
{ push_arg(arg, this); push_arg(args...); }
};


The overloaded engine class remains the same. The changes are instead added to the application code as translator specializations:

template <>
void push_arg<IActor*>(IN IActor* arg, IN scriptengine* eng)
{
luaengine* luaEng = static_cast<luaengine*>(eng);
luaEng->push_arg(arg);
}

template <>
void push_arg<const char*>(IN const char* arg, IN scriptengine* eng)
{
luaengine* luaEng = static_cast<luaengine*>(eng);
luaEng->push_arg(arg);
}

template <>
void push_arg<float>(float arg, IN scripting::engine* eng)
{
luaengine* luaEng = static_cast<luaengine*>(eng);
luaEng->push_arg(arg);
}

// ... and so forth for all supported data types


It's actually really simple, but in all honesty I'd been pondering on and off as to how to pull it off for several weeks now.

Working with templates is, more often than not, like dancing tango on a melting raft made of ice. With a polar bear. There's usually a solution, but first you have to something about the polar bear.

Edited by irreversible