避免模​​板特化中的构造函数重复

时间:2014-05-06 18:02:20

标签: c++ templates template-specialization

假设我有一个基类,它存储对某些class Bar的引用:

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

  // Some other functions

protected:
  Bar &_barCtx;
};

我想要做的是在此基础上添加一定程度的继承,其中class Foo<T>将添加一些功能。

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

然后,有些Foo<T>的实例需要提供不同版本的doSomething(),因此使用模板专精。问题是,在Foo<>的每个专用版本中,我必须重新实现构造函数并将Bar的引用传递给超类。这基本上是复制和粘贴代码,我想避免使用。

class Baz;

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

本练习的目的是提供不同类型的doSomething(),具有不同的签名。因此,如果不使用C ++ 11(因为我坚​​持使用GCC 4.6.3),有没有办法避免这种代码重复?或者,有没有更好的方法来提供不同的doSomething()

3 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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";
  }
};

(由于您无法使用C ++ 11,请将std::enable_ifstd::is_same替换为boost版本或您自己的版本。)

答案 2 :(得分:1)

这似乎是使用模板专业化的错误位置。模板类型没有在声明中的任何地方使用,所以它完全是任意的。

我建议使用其他技术

1)为您的输入定义一个抽象基类型,并且doSomething可以接受任何实现。

bool doSomething(DoSomethingParamsBase* params);

2)使用带有可变参数的枚举MODE参数

bool doSomething(MODE mode...);