Avoid duplicate constructor in specialization

Suppose I have a base class that stores a reference to some class Bar:

class FooBase
{
public:
  FooBase( Bar &ctx ) : _barCtx( ctx ) {};
  virtual ~FooBase() {};

  // Some other functions

protected:
  Bar &_barCtx;
};

What I would like to do is add an inheritance level on top of this, where it class Foo<T>will add some features.

template< typename T >
class Foo : public FooBase
{
public:
  Foo( Bar &ctx ) : FooBase( ctx ) {};
  bool doSomething( int a );
};

Then there are several instances Foo<T>that should offer a different version doSomething(), therefore, specialized specialization is used. The problem is in each specialized version Foo<>, I have to re-implement the constructor and pass the link to the Barsuperclass. This is basically copy and paste code that I would like to avoid.

class Baz;

template<>
class Foo<Baz> : public FooBase
{
public:
  Foob( Bar &ctx ) : FooBase( ctx ) {};
  bool doSomething( std::string &str, int x, float g );
};

- doSomething() . , ++ 11 ( GCC 4.6.3), ? , doSomething()?

+4
3

, SFINAE , - - , - . , , . , , .

- CRTP. .

:

#include <string>

class Bar {};

class FooBase
{
public:
  FooBase( Bar &ctx ) : _barCtx( ctx ) {};
  virtual ~FooBase() {};
protected:
  Bar &_barCtx;
};

template< typename T >
class Foo : public FooBase
{
public:
  Foo( Bar &ctx ) : FooBase( ctx ) {};
  bool doSomething( int a ) { return true; }
  // Declared, but not defined.
  bool doSomething( std::string &str, int x, float g );
};

class Baz {};

// Declared, but not defined.
template <>
bool
Foo<Baz>::doSomething(int i);

template <>
bool
Foo<Baz>::doSomething(std::string &str, int x, float g) {
    return true;
}

int main() {
    Bar b;
    Foo<int> f1(b);
    std::string s;

    f1.doSomething(1); // Compiles.
    // f1.doSomething(s, 1, 3.14f); // Link error.

    Foo<Baz> f2(b);
    // f2.doSomething(1); // Link error.
    f2.doSomething(s, 1, 3.14f); // Compiles.
}

CRTP-:

#include <string>

class Bar {};
class Baz {};

template <typename T>
class Spec {
    public:
        bool doSomething( int a );
};

template <>
class Spec<Baz> {
    public:
        bool doSomething( std::string &str, int x, float g );
};

class FooBase {
    public:
        FooBase( Bar &ctx ) : _barCtx( ctx ) {};
        virtual ~FooBase() {};
    protected:
        Bar &_barCtx;
};

template< typename T >
class Foo : public FooBase, public Spec<T> {
    public:
        Foo( Bar &ctx ) : FooBase( ctx ) {};
};

template <typename T>
bool Spec<T>::doSomething( int a ) {
    Foo<T> *fp = static_cast<Foo<T> *>(this);
    return true;
}

bool Spec<Baz>::doSomething( std::string &str, int x, float g ) {
    Foo<Baz> *fp = static_cast<Foo<Baz> *>(this);
    return true;
}

int main() {

    Bar b;
    std::string s;

    Foo<int> f1(b);
    f1.doSomething(1);

    Foo<Baz> f2(b);
    f2.doSomething(s, 1, 3.14f);
}
+3

Foo , SFINAE:

template< typename T >
class Foo : public FooBase
{
public:
  Foo( Bar &ctx ) : FooBase( ctx ) {};

  template<
    typename U = T,
    typename = typename std::enable_if<!std::is_same<U, Baz>::value>::type>
  bool doSomething( int a )
  {
      std::cout << "doSomething( int a )\n";
  }

  template<
      typename U = T,
      typename = typename std::enable_if<std::is_same<U, Baz>::value>::type>
  bool doSomething( std::string &str, int x, float g )
  {
      std::cout << "doSomething( std::string &str, int x, float g )\n";
  }
};

( ++ 11, std::enable_if std::is_same .)

+3

. , .

1) doSomething .

bool doSomething(DoSomethingParamsBase* params);

2) MODE ,

bool doSomething(MODE mode...);
+1
source

Source: https://habr.com/ru/post/1539477/


All Articles