Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
实现';有界泛型';在C++; 我把一个项目从java转移到C++,在java中有一些比较简单的问题。_C++_Templates_Generics - Fatal编程技术网

实现';有界泛型';在C++; 我把一个项目从java转移到C++,在java中有一些比较简单的问题。

实现';有界泛型';在C++; 我把一个项目从java转移到C++,在java中有一些比较简单的问题。,c++,templates,generics,C++,Templates,Generics,我有一个类X,用于处理Y类型的对象和从Y继承的对象X通常需要从Y调用一个方法,比如说kewl\u method(),这个方法在继承自Y的每个类中都是不同的。在Java中,我可以这样做: public class X<y extends Y> 公共类X 我会在X中调用kewl\u method(),而不会感到头痛,它会做我想做的事情。如果我理解正确(我是C++新手),C++中没有这样的有界泛型,所以如果我使用一个模板,它有“代码> x ,那么它就可以完全填充任何东西,而我不能调用

我有一个类
X
,用于处理
Y
类型的对象和从
Y
继承的对象
X
通常需要从
Y
调用一个方法,比如说
kewl\u method()
,这个方法在继承自
Y
的每个类中都是不同的。在Java中,我可以这样做:

public class X<y extends Y>
公共类X
我会在
X
中调用
kewl\u method()
,而不会感到头痛,它会做我想做的事情。如果我理解正确(我是C++新手),C++中没有这样的有界泛型,所以如果我使用一个模板,它有“代码> x <代码>,那么它就可以完全填充任何东西,而我不能调用<代码> KeWLL方法()/<代码>的变体。 在C++中,最好的方法是什么?使用石膏


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

如果我理解正确,将
Y::kewl\u方法
虚拟化将是一个很好的Java翻译。您不希望在派生自
Y

的类中重载它,只需按如下方式键入它:

template<class T>
void method()
{
   T t;
   t.kewl_method();
}
模板
void方法()
{
T;
t、 kewl_方法();
}

如果您以错误的方式使用它,编译器将给您一个错误,即kewl_method()不是[type of T]的成员

您在Java中所指的构造是泛型。在C++中最接近的对应的东西是模板。 因此,C++中所呈现的最接近的翻译将是

template<class T>
class X
{
    // Here you use T as Y or type derived from it
    // for example
    void method(T& y)
    {
        y.kewl_method();
    }
};
你也可以使用

X<Z> b;
xb;

这是可以接受的。在C++中,模板是鸭式的,即您可以调用任何类型的<代码> t>代码>,只要实际指定的类型有此方法,它就正确了。

我理解,您要强制传递给您的类模板的模板参数是从某个<代码>类y继承的。我应该注意到,您不能使用boost是非常不幸的。我将提供一个带有boost的解决方案

template <class T, bool OK> class XImpl; //no definition, just declaration
template <class T> class XImpl<T, true> //partial specialization
{
    //here goes your real class definition
};
template <class T> class X : public XImpl<T, boost::is_base_and_derived<Y, T>::value >
{}; //if T isn't derived from Y, compilation will fail because you are trying to 
    //inherit from an incomplete (undefined) type 
模板类XImpl//没有定义,只有声明
模板类XImpl//部分专门化
{
//这是您真正的类定义
};
模板类X:公共XImpl
{}; //如果T不是从Y派生的,编译将失败,因为您正在尝试
//从不完整(未定义)类型继承

我们使用的唯一
boost
部分是
基于和派生的
元函数。您可以查看boost源代码,了解它是如何实现的,然后自己实现它。HTH

使用模板,但对其工作的类型进行限制:

template<typename T>
void
X::some_member(T& t)
{
    // Triggers a compile-time error if/when T is not derived from Y
    STATIC_ASSERT(( is_base_of<Y, T> ));
    t.kewl_method();
}
模板
无效的
X::一些_成员(T&T)
{
//如果T不是从Y派生的,则触发编译时错误
静态断言((是的基);
t、 kewl_方法();
}
因为您没有使用Boost,所以必须实现
静态断言
,并且
的基础。第一个有点简单,但第二个不是这样(尽管你可以使用一个可转换的特征作为近似值)。

(was:heishe),就我而言

但我想谈谈你的问题:

所以,如果我使用一个带有X的模板,就可以用任何东西来填充它

不,因为如果没有可访问的
kewl\u方法
,它将无法编译

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

在C++中,这个特性是按编译器的使用方式提供的:以类似于鸭类型的方式,但在编译时解决,编译器将只在泛型类型类访问“代码> KeWLIHead < /COD> > < /P>时接受该方法的编译。 关于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() ;
        }
} ;
您需要调用
foo()
方法来阻止编译

如果真的需要约束怎么办? 如果要显式地将其限制为从X继承的类,则必须自己使用代码(直到标准化这些类…它们错过了C++0x截止日期,所以我想我们必须等待下一个标准…)

如果您真的想设置约束,有多种方法。虽然我知道这一点,但我对这个概念还不够熟悉,无法为您提供解决方案,但我仍然可以看到两种方法来为您的案例应用约束(虽然它们是针对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() ;
        }
} ;
但是,作为示例,您需要调用
foo()
方法来阻止编译

在类中添加自制的“约束”? 让我们创建一个类来表示其构造函数上的约束:

template<typename T, typename T_Base>
class inheritance_constraint
{
    public:
        inheritance_constraint()
        {
            const T_Base * t = static_cast<const T *>(NULL) ;
        }
} ;
模板
类继承约束
{
公众:
继承约束()
{
const T_Base*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() ;
        }
} ;
模板
类C:继承\约束//我们希望T从X派生
{
公众:
void foo()
{
T;
t、 kewl_方法();
}
} ;
私有继承意味着您的“继承_约束”不会影响您的代码,但它仍然在编译时表示一个约束,该约束将停止对不是从X派生的类T的编译:

结果将是:

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;
}
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 ;
}
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 ;
}
intmain()
{
//C的约束是:实现kewl_方法,并且
template<typename T>
class C : inheritance_constraint<T, X> // we want T to derive from X
{
    public :
        void foo()
        {
            T t ;
            t.kewl_method() ;
        }
} ;
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 ;
}