Dual implementations without polymorphism in C++

Started by
5 comments, last by Julian90 16 years, 11 months ago
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.
Advertisement
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.

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

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.
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 isclass 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.
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;};
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]
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.

This topic is closed to new replies.

Advertisement