假设我有一个基类,它存储对某些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()
?
答案 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_if
和std::is_same
替换为boost版本或您自己的版本。)
答案 2 :(得分:1)
这似乎是使用模板专业化的错误位置。模板类型没有在声明中的任何地方使用,所以它完全是任意的。
我建议使用其他技术
1)为您的输入定义一个抽象基类型,并且doSomething可以接受任何实现。
bool doSomething(DoSomethingParamsBase* params);
或
2)使用带有可变参数的枚举MODE参数
bool doSomething(MODE mode...);