0

To be honest, I dislike virtual dispatching, Interface class. For that reason I want implement own classes without any base abstract class. To be image, I am implementing MyCustomWidget and its some methods have been implemented, others no, because it's not necessary.

// here is my custom widget class, which 'show' method is implemented, but 'close' method is not.
struct MyCustomWidget
{
    void show(){ std::cout << "Hey" << std::endl; }
    //void close(){ std::cout << "Bye"  << std::endl; }
};

// here is your custom widget class, which 'show' is not implemented but 'close' is .
struct YourCustomWidget
{
    //void show(){}
    void close(){ std::cout << "Bye" << std::endl;}
};

// common widget class, which may stored within any custom widgets.
struct Widget
{
    Widget() = default;

    template< typename CustomWidget >
    void add(CustomWidget cw)
    {
        auto child = std::make_unique< proxy<CustomWidget> >( std::move( cw ) )
        childs.push_back( std::move(child ) );
    }
    void show()
    {
        for(auto & e : childs) 
            e->show();
    }
    void close()
    {
        for(auto& e : childs)
            e->close();
    }
private:
    struct proxy_base
    {
        virtual void show() = 0;
        virtual void close() = 0;
        virtual ~proxy_base(){}
    };

    template< typename CustomWidget >
    struct proxy : public proxy_base
    {
        explicit proxy(CustomWidget cw_) : cw( std::move(cw_ ) ) 
        {}

        void show() override final
        {    // -------------->>>>>> (1)
            // call cw.show()  if cw has 'show' method, otherwise nothing.
        }
        void close() override final
        {     /// ---------------->>>> (2)
            // call cw.close if cw has a 'close' method, otherwise nothing.
        }

        CustomWidget cw;
    };

std::vector< std::unique_ptr< proxy_base > >childs;
};

int main()
{
     Widget w;
     w.add( MyCustomWidget() );
     w.add( YourCustomWidget() );

     w.show();
     //.... a lot of code

     w.close();
}

My Question is simple: how me implement that (1) and (2) virtual methods ?

Edit: I see that question already has been answered. Let me change my question. Q2: (1) and (2) methods are 'final' and in base class they were declared as pure virtual, for this situation compiler can optimize virtual table, and avoid it ? I'm interesting in GCC, CLang and Visual Studio 2013.

Khurshid
  • 2,654
  • 2
  • 21
  • 29
  • possible duplicate of [Is it possible to write a C++ template to check for a function's existence?](http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence) – KeatsPeeks Feb 18 '14 at 18:01
  • I think the SFINAE idiom addresses your issue perfectly, see the answer to the question I marked as a duplicate – KeatsPeeks Feb 18 '14 at 18:03
  • ouh, greate!!! Thanks. – Khurshid Feb 18 '14 at 18:03
  • 1
    I really don't see the point in jumping through all these hoops to get rid of a couple of virtual function pointers. The time needed to reference them will be utterly neglectible compared with the typical volume of code for a GUI function, so performance is hardly an issue there. You can easily produce a default virtual method at the top of the inheritance chain and get rid of the problem. In comparison, the template goo is making the code bloated, unreadable and slow to compile (and will spout eye-watering error messages to punish you for the slightest typo). Hardly a good swap, IMHO. – kuroi neko Feb 18 '14 at 18:17
  • That is only an example, I am not a GUI programmer. But I am agree with you. – Khurshid Feb 18 '14 at 18:24
  • @kuroineko - right. The C++XX committee seems to treat anything `virtual` as a crazy uncle they had nothing to do with. – Brett Hale Feb 18 '14 at 18:24
  • lol @Brett. Maybe the committee is anxious to remove all traces of mechanisms you would not need a few years to learn and a couple of decades to master? – kuroi neko Feb 18 '14 at 18:32
  • Consider that the part of the standard library that most extensively and visibly uses runtime polymorphism is iostreams. That's why. – Casey Feb 18 '14 at 18:59

2 Answers2

3

You can put these in the private section of proxy class:

template<typename T>
auto show_helper(int) -> decltype( std::declval<T>().show(), void())
{
    cw.show();
}

template<typename T>
void show_helper(...) { }

and call them like this from show:

show_helper<CustomWidget>(0);

The first overload gets instantiated only if expression in trailing return type is well formed, that is, when T has got show method.

This is called expression SFINAE and is much shorter than pre-C++11 version from pmr's answer. It's also more flexible as it lets you specify the signature of show more easily. The other answer can give you positive result only to discover that you can't call show without arguments. Pick your poison.

Live example.

jrok
  • 54,456
  • 9
  • 109
  • 141
  • Yeah, at some point I need to start using a new technique for this. It's just that I reflexively choose the older one. – pmr Feb 18 '14 at 21:03
1

You can get a SFINAE traits class to check and then use this to dispatch on an close_impl. Alternatively, you also use the traits class in combination with enable_if to chose the right version of close.

#include <iostream>
#include <type_traits>

template <typename T>
class has_close
{
  typedef char one;
  typedef long two;

  template <typename C> static one test( decltype(&C::close) ) ;
  template <typename C> static two test(...);
public:
  enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

struct X { void close() {} };
struct X1 { };

template<typename T>
struct XX {
  T t;

  void close() {
    close_impl(std::integral_constant<bool, has_close<T>::value>{});
  }

  void close_impl(std::true_type) { std::cout << "call close" << std::endl;t.close(); }
  void close_impl(std::false_type) { std::cout << "no close" << std::endl;}
};

int main()
{
  XX<X> x; x.close();
  XX<X1> x1; x1.close();
  return 0;
}
pmr
  • 58,701
  • 10
  • 113
  • 156