[英]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_if
和std::is_same
為boost版本或您自己的版本。)
這似乎是使用模板專業化的錯誤位置。 模板化類型沒有在聲明中的任何地方使用,所以它完全是任意的。
我建議使用其他技術
1)為您的輸入定義一個抽象基類型,並在任何實現中使用doSomething。
bool doSomething(DoSomethingParamsBase* params);
要么
2)使用帶有可變參數的枚舉MODE參數
bool doSomething(MODE mode...);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.