Sign in to follow this  

Dual implementations without polymorphism in C++

This topic is 3846 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

Consider RPC:
class SomeInterface {
  virtual void foo() = 0;
}

class LocalInterface {
  virtual void foo() {
    // do the foo
  }
}

class RemoteInterface {
  virtual void foo() {
    // marshall the method
    // send over network
  }
}


Is there a way to do this without virtual functions? The reason I ask is because when implementing such system with automatic co-location detection, local interface can be very tightly bound into the application. One way is to provide two cpp files, one for each interface, and use separate linking. But this makes it impossible to allocate objects during run-time, since their remote/local instance needs to be determined during compilation. Is there some template magic that could be used for this? I realize that compared to overhead of network call, virtual function overhead is negligible. Unlike usual polymorphism, there will always be only two roles. Local and remote. Interfaces would also be automatically generated, so code verbosity isn't an issue. Function overloads perhaps, where one uses a parameter designating local/remote execution? I'm just brainstorming over possible ideas. The only goal is an attempt to eliminate the overhead during local execution, even at possible slight cost at remote execution.

Share this post


Link to post
Share on other sites
Hmm, how about something with function pointers? Upon object instantiation specify which implementation to use and then when you call that method have it in turn call the appropriate function. You would need to pass all needed variables to the function though, I believe.

How's that sound? Others, please criticize :)

edit: my own criticism would be that this would increase overhead which you didn't want. Forget it.

Share this post


Link to post
Share on other sites
Quote:
Hmm, how about something with function pointers? Upon object instantiation specify which implementation to use and then when you call that method have it in turn call the appropriate function. You would need to pass all needed variables to the function though, I believe.


virtual functions are implemented as function pointers behind the scenes in general so I don't think that would we an acceptable solution since it would have the same overhead.

Looks to me like what you want is the CRTP

Edit: Just a note that assumes you know which one you need at compile time.

Share this post


Link to post
Share on other sites
Silly, me, forgot to list the reason why I want this.

Templated functions.

Use case is this:

...
// here I don't know whether ServicePtr is local or remote
ServicePtr service = SomeBroker.resolve("ServiceName");
service->foo(17);
service->foo("Hello");
...

// where service is
class ServiceIF
{
template < typename T >
void foo( T value );
}






That's the reason why no virtual methods.

So with this in mind, the following would work:

template < class Connection, class ServiceImpl >
class ServiceIF : private ServiceImpl
{
template < typename T >
void foo( T value )
{
if (m_is_local) {
m_impl.foo(value);
} else {
m_connection.foo(value);
}
}
private:
bool m_is_local;
ServiceImpl m_impl;
Connection m_connection;
}





I'm just interested if someone has a an alternate aproach, or better idea, perhaps some boost magic.

Share this post


Link to post
Share on other sites
Looks like what you want is a boost::variant then, something like the following?

template < class Connection, class ServiceImpl >
class ServiceIF
{
template<typename T>
struct apply_foo : boost::static_visitor<void>
{
apply_foo(T& t): value(t) { }

void operator()(ServiceImpl& impl)
{ impl.foo(value); }

void operator()(Connection& connection)
{ connection.foo(value); }

boost::reference_wrapper<T> value;
}

template < typename T >
void foo( T value )
{
boost::apply_visitor(apply_foo(value), m_impl);
}

private:
boost::variant<ServiceImpl, Connection> m_impl;
};


Share this post


Link to post
Share on other sites
Quote:
Original post by Julian90
Looks like what you want is a boost::variant then, something like the following?
*** Source Snippet Removed ***


Hmmm, if this compiles with low overhead, which given templated nature it might, and without extra parameter copying, then that would be an ideal solution.

I just need to look at how variant works. Hopefully not through some excessive function pointer usage.

And variant used in this way would make a perfect place for event multicasting as well.

Meditate on this I must. Unless there's some hidden catch in there, this would be by far the most elegant solution I could think of.

Edit:
Sadly it results in insane code bloat. A switch statement with 20 cases. A single if test is nothing compared to that. With all optimizations turned on, so it seems to be normal way variant works.

But perhaps I can extract enough from variant implementation to just use the specific case.

Edit2:
Turns out it's a MVS optimization thing. Under certain settings it's capable of generating perfectly inline code without any overhead at all.

Guess I'll need to profile, but I believe this is what I'll go with. It's a clean solution.

[Edited by - Antheus on May 31, 2007 8:14:01 PM]

Share this post


Link to post
Share on other sites
Quote:
Edit2:
Turns out it's a MVS optimization thing. Under certain settings it's capable of generating perfectly inline code without any overhead at all.

Guess I'll need to profile, but I believe this is what I'll go with. It's a clean solution.


Interesting, well I wouldn't blame the compiler too much since boost::variant jumps through a heap of hop's to try and allocate it on the stack without wasting storage. Still good to know in case I ever run into it.

Share this post


Link to post
Share on other sites

This topic is 3846 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.

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