gpt4 book ai didi

c++ - 在 C++ 中实现 'bounded genericity'

转载 作者:可可西里 更新时间:2023-11-01 18:06:18 24 4
gpt4 key购买 nike

我正在将一个项目从 Java 转移到 C++,但我在 Java 中遇到了一些相对简单的问题。

我有一个类X用于处理 Y 类型的对象和从 Y 继承的对象. X经常需要从 Y 调用一个方法,说 kewl_method() ,而且这个方法在每个继承自Y的类中都不一样.在 Java 中,我可以做这样的事情:

public class X<y extends Y>

我会打电话 kewl_method()X没有任何头痛,它会做我想做的。如果我理解正确(我是 C++ 的新手),那么 C++ 中没有有限泛型这样的东西,所以如果我使用带有 X 的模板完全可以用任何东西填充它,我将无法调用 kewl_method() 的变体.

在 C++ 中执行此操作的最佳方法是什么?使用类型转换?

限制:我不能使用 boost 或 TR1。

最佳答案

TravisG (原为:heishe)already answered ,就我而言。

但我想评论你的问题:

so if I use a template with X it would be possible to fill it with absolutely anything



不,因为如果没有可访问的 kewl_method,它将无法编译.

您必须记住,在 Java 中,有界泛型不是像您认为的那样限制泛型类接受的类型,而是更多地为泛型类提供有关其泛型类型 T 的更完整信息,以便能够验证调用在编译时到它的方法。

在 C++ 中,此功能由编译器按原样提供并在何处使用:以类似于鸭子类型的方式,但在编译时解析,编译器仅在泛型类型具有访问权限时才会接受方法的编译到 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. */ }
} ;

普通C++解决方案

使用 C++ 模板,您可以提供模板化的类 A:
template<typename T>
class A
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;

...使用 X、Y 和 Z 类,而不是 K,因为:
  • X : 它实现了 kewl_method()
  • Y :它公开派生自 X,它实现了 kewl_method()
  • Z :它实现了 kewl_method()
  • K :它没有实现 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;
    }

    您需要调用 foo()阻止编译的方法。

    如果真的需要约束怎么办?

    如果你想明确地限制从 X 继承的类,你必须自己做,使用代码(直到 C++ concepts 被标准化......他们错过了 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() ;
    }
    } ;

    其中,当 B::foo() 被调用时,只有在 T* 时才会编译可铸成 X* (只有通过公共(public)继承才有可能)。

    结果是:
    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 ;
    }

    但是,作为 A 示例,您需要调用 foo()阻止编译的方法。

    给一个类(class)添加一个本土的“约束”?

    让我们创建一个类来表达对其构造函数的约束:
    template<typename T, typename T_Base>
    class inheritance_constraint
    {
    public:
    inheritance_constraint()
    {
    const T_Base * t = static_cast<const T *>(NULL) ;
    }
    } ;

    你会注意到这个类是空的,它的构造函数什么都不做,所以很有可能它会被优化掉。

    您将在以下示例中使用它:
    template<typename T>
    class C : inheritance_constraint<T, X> // we want T to derive from X
    {
    public :
    void foo()
    {
    T t ;
    t.kewl_method() ;
    }
    } ;

    私有(private)继承意味着您的“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 ;
    }

    问题在于它依赖于继承和构造函数调用才能生效。

    添加带有函数的本土“约束”?

    这个约束更像是一个静态断言,在调用方法时进行测试。一、约束函数:
    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) ;
    } ;

    然后使用它的类:
    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 ;
    }

    但是,作为 A 和 B 示例,您需要调用 foo()阻止编译的方法。

    结论

    您必须根据自己的特定需求在上述方法之一中进行选择。

    但通常,就我而言,我发现所有这些都有些矫枉过正,我会使用上面第一个更简单的解决方案。

    编辑 2011-07-24

    添加了另一部分代码,通过简单的函数调用来表达约束。

    在“添加未使用的类型转换?”部分,我替换了引用类型转换 X & x = t ;使用指针转换(如在其他部分中),我认为这更好。

    为了让 Caesar 得到应有的返回,指针转换最初的灵感来自于 now deleted answer 中的一行代码。的 Jonathan Grynspan .

    关于c++ - 在 C++ 中实现 'bounded genericity',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6803100/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com