PhD*_*hDP 7 c++ generics templates
我正在将一个项目从Java转移到C++,而我在Java中遇到一些相对简单的问题.
我有一个类X
来处理Y
从中继承的类型和对象的对象Y
.X
经常需要调用一个方法Y
,比方说kewl_method()
,这个方法在继承的每个类中都是不同的Y
.在Java中,我可以这样做:
public class X<y extends Y>
Run Code Online (Sandbox Code Playgroud)
我所说的kewl_method()
在X
没有任何头痛,它会做我想做的.如果我理解正确(我是C++的新手),在C++中没有有限的通用性,所以如果我使用模板X
就可以用绝对的东西填充它,我将无法调用的变种kewl_method()
.
在C++中执行此操作的最佳方法是什么?使用演员?
限制:我不能使用boost或TR1.
pae*_*bal 15
但我想评论你的问题:
因此,如果我使用带有X的模板,则可以填充绝对任何东西
不,因为如果没有可访问的话就无法编译kewl_method
.
你必须记住,在Java中,有限的通用性不是像你想象的那样限制你的泛型类接受的类型,而是更多关于为泛型类提供关于其泛型类型T的更完整信息以便能够验证调用编译时的方法.
在C++中,此功能按原样提供并由编译器使用:在类似于duck typing的方式中,但在编译时解析,只有在泛型类具有访问权限时,编译器才会接受方法的编译到了kewl_method
.
有关4个类的示例:
class X
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class Y : public X
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class Z
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class K
{
public : virtual void wazaa() { /* etc. */ }
} ;
Run Code Online (Sandbox Code Playgroud)
使用C++模板,您可以提供模板化的类A:
template<typename T>
class A
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;
Run Code Online (Sandbox Code Playgroud)
...与X,Y和Z类,但不是K,因为:
kewl_method()
kewl_method()
kewl_method()
kewl_method()
...它比Java(或C#)的泛型更强大.用户代码是:
int main()
{
// A's constraint is : implements kewl_method
A<X> x ; x.foo() ; // OK: x implements kewl_method
A<Y> y ; y.foo() ; // OK: y derives from X
A<Z> z ; z.foo() ; // OK: z implements kewl_method
A<K> k ; k.foo() ; // NOT OK : K won't compile: /main.cpp error:
// ‘class K’ has no member named ‘kewl_method’
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您需要调用该foo()
方法来阻止编译.
如果你想明确地将它限制为继承自X的类,你必须自己使用代码来做(直到C++概念被标准化......他们错过了C++ 0x截止日期,所以我想我们将不得不等待下一个标准...)
如果你真的想放置约束,有多种方法.虽然我知道这一点,但我对SFINAE概念不够熟悉,无法为您提供解决方案,但我仍然可以看到两种方法为您的案例应用约束(虽然它们经过了g ++ 4.4.5的测试,但有人可以更聪明地验证我的代码?):
B类类似于A类,另外还有一行代码:
template<typename T> // We want T to derive from X
class B
{
public :
void foo()
{
// creates an unused variable, initializing it with a
// cast into the base class X. If T doesn't derive from
// X, the cast will fail at compile time.
// In release mode, it will probably be optimized away
const X * x = static_cast<const T *>(NULL) ;
T t ;
t.kewl_method() ;
}
} ;
Run Code Online (Sandbox Code Playgroud)
当调用B :: foo()时,只有在T*
可以强制转换时才会编译X*
(只有通过公共继承才能进行编译).
结果将是:
int main()
{
// B's constraint is : implements kewl_method, and derives from X
B<X> x ; x.foo() ; // OK : x is of type X
B<Y> y ; y.foo() ; // OK : y derives from X
B<Z> z ; z.foo() ; // NOT OK : z won't compile: main.cpp| error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
B<K> k ; k.foo() ; // NOT OK : K won't compile: /main.cpp error:
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
但是,作为A示例,您需要调用该foo()
方法来阻止编译.
让我们创建一个在其构造函数上表达约束的类:
template<typename T, typename T_Base>
class inheritance_constraint
{
public:
inheritance_constraint()
{
const T_Base * t = static_cast<const T *>(NULL) ;
}
} ;
Run Code Online (Sandbox Code Playgroud)
你会注意到这个类是空的,它的构造函数什么都不做,所以很有可能它会被优化掉.
您将使用它,如以下示例所示:
template<typename T>
class C : inheritance_constraint<T, X> // we want T to derive from X
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;
Run Code Online (Sandbox Code Playgroud)
私有继承意味着你的"inheritance_constraint"不会搞砸你的代码,但它仍然在编译时表达一个约束,该约束将停止不从X派生的类T的编译:
结果将是:
int main()
{
// C's constraint is : implements kewl_method, and derives from X
C<X> x ; // OK : x is of type X
C<Y> y ; // OK : y derives from X
C<Z> z ; // NOT OK : z won't compile: main.cpp error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
C<K> k ; // NOT OK : K won't compile: /main.cpp error:
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
问题是它依赖于继承和构造函数调用才有效.
此约束更像是静态断言,在调用方法时进行测试.一,约束功能:
template<typename T, typename T_Base>
void apply_inheritance_constraint()
{
// This code does nothing, and has no side effects. It will probably
// be optimized away at compile time.
const T_Base * t = static_cast<const T *>(NULL) ;
} ;
Run Code Online (Sandbox Code Playgroud)
然后使用它的类:
template<typename T>
class D
{
public :
void foo()
{
// Here, we'll verify if T inherits from X
apply_inheritance_constraint<T, X>() ;
T t ;
t.kewl_method() ;
}
} ;
int main()
{
// D's constraint is : implements kewl_method, and derives from X
D<X> x ; // OK : x is of type X
D<Y> y ; // OK : y derives from X
D<Z> z ; // NOT OK : z won't compile: main.cpp error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
D<K> k ; // NOT OK : K won't compile: /main.cpp 2 errors:
// ‘class K’ has no member named ‘kewl_method’
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
Run Code Online (Sandbox Code Playgroud)
但是,作为A和B示例,您需要调用该foo()
方法来阻止编译.
您必须根据您的具体需求在上述方法之一中进行选择.
但通常,就我而言,我发现所有这些都太过分了,我会使用上面第一个更简单的解决方案.
添加了另一个带有代码的部分,通过简单的函数调用来表达约束.
在"添加未使用的演员阵容?" 部分,我用X & x = t ;
指针转换替换了引用转换(如在其他部分中),我认为这更好.
为了给凯撒带来应有的价值,指针演员最初的灵感来自Jonathan Grynspan 现在删除的答案中的一行代码.
归档时间: |
|
查看次数: |
3125 次 |
最近记录: |