C ++ template class refactoring based on template type

This class is Foo

template <typename T>
class Foo
{
public:

  ...other methods..

  void bar()
  {
    ...
    m_impl.doSomething();
    ...
  }

  void fun()
  {
    ...
    m_impl.doSomethingElse();
    ...
  }

  void fubar()
  {
    ...
  }

private:
  T m_impl;
};

I wanted to serve situations where T is boost :: shared_ptr. In this case, the only change to the Foo class is that it should call

m_impl->doSomething();

instead

m_impl.doSomething();

I ended up defining FooPtr in the same header

template <typename T>
class FooPtr
{
public:
  ...other methods..

  void bar()
  {
    ...
    m_pImpl->doSomething();
    ...
  }

  void fun()
  {
    ...
    m_pImpl->doSomethingElse();
    ...
  }

  void fubar()
  {
    ...
  }

private:
  boost::shared_ptr<T> m_pImpl;
};

Now that the approach works for all the classes that I want to use with Foo, the problem is that I have a lot of duplicate code, and all the changes I make Foo, I also need to make FooPtr.

How can I reorganize the code? For instance. Is there a way that I can determine at compile time if T is of type boost :: shared_ptr and then specializes only in bar and fun methods to call the → operator?

: ! , , .

2: @Matthieu: ,

class FooImpl
{
public:
  void doIt()
  {
    cout << "A" << std::endl;
  }
};

int _tmain(int argc, _TCHAR* argv[])
{
  Foo<FooImpl> foo;
  foo.doSomething();
  return 0;
}
+3
6

Sylvain DRY-, .

- , , !

namespace details {
  template <typename T>
  struct FooDeducer {
    typedef boost::optional<T> type;
  };

  template <typename T>
  struct FooDeducer< T* > {
    typedef T* type;
  };

  template <typename T>
  struct FooDeducer< boost::shared_ptr<T> > {
    typedef boost::shared_ptr<T> type;
  };
} // namespace details

template <typename T>
class Foo {
public:
  // methods
  void doSomething() { impl->doIt(); }

private:
  typedef typename details::FooDeducer<T>::type Type;
  Type impl;
};

, boost::optional, OptionPointee, , .

, , - . boost::optional .

+4
class A
{
public:
    void doSomething() {}
};
template <typename T>
class Foo
{
public:
  void bar()
  {
    Impl(m_impl).doSomething();
  }

private:
    template<typename P>
    P& Impl(P* e)
    {
        return *e;
    }
    template<typename P>
    P& Impl(std::shared_ptr<P> e)
    {
        return *e;
    }
    template<typename P>
    P& Impl(P& e)
    {
        return e;
    }
  T m_impl;
};
+2

caller, - , obj.f() obj->f(), obj.

, :

template<typename T>
struct caller
{
    static void call(T &obj) {  obj.f(); } //uses obj.f() syntax
};

template<typename T>
struct caller<T*>
{
    static void call(T* obj) {  obj->f(); } //uses obj->f() syntax
};

caller :

template<typename T>
struct X
{
   T obj;
   X(T o) : obj(o) {}
   void h()
   {
        caller<T>::call(obj); //this selects the appropriate syntax!
   }
};

- ideone: http://www.ideone.com/H18n7

-

EDIT:

. , , caller. caller , !

http://www.ideone.com/83H52

+2

, - :

template < typename T >
class FooBase
{
private:
    T m_impl;

protected:
    T& impl() { return m_impl; }
};

template < typename T >
class FooBase< boost::shared_ptr< T > >
{
private:
    boost::shared_ptr< T > m_impl;

protected:
    T& impl() { return *(m_impl.operator ->()); }
};

template < typename T >
class Foo : protected FooBase< T >
{
public:
    void bar()
    {
        impl().DoSomething();
    }
};

Foo . , FooBase.

: Foo FooBase ( , , FooHelper - ).

template < typename T >
class FooHelper
{
private:
    T m_impl;

public:
    T& impl() { return m_impl; }
};

template < typename T >
class FooHelper< boost::shared_ptr< T > >
{
private:
    boost::shared_ptr< T > m_impl;

public:
    T& impl() { return *(m_impl.operator ->()); }
};

template < typename T >
class Foo
{
private:
    FooHelper< T > m_helper;

public:
    void bar()
    {
        m_helper.impl().DoSomething();
    }
};
+1

, . , , , .

Do you really need a copy? If you need to change the way an object is represented, this should be done as a separate exercise, not part of the template that uses it.

+1
source

You can use partial specialization.

template <typename T>
class Foo
{
public:
  //...
};

template<typename T> class Foo<boost::shared_ptr<T>> {
  //... implement specialization here
};
0
source

All Articles