簡體   English   中英

避免模​​板特化中的構造函數重復

[英]avoid constructor duplication in 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()

我實際上認為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);
}

您可以提供每個重載,而不是專門化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版本或您自己的版本。)

這似乎是使用模板專業化的錯誤位置。 模板化類型沒有在聲明中的任何地方使用,所以它完全是任意的。

我建議使用其他技術

1)為您的輸入定義一個抽象基類型,並在任何實現中使用doSomething。

bool doSomething(DoSomethingParamsBase* params);

要么

2)使用帶有可變參數的枚舉MODE參數

bool doSomething(MODE mode...);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM