[英]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.