具有非指针/引用返回类型的协变返回类型

时间:2012-05-25 17:52:14

标签: c++ pointers ienumerable return-type covariant

我正在尝试在C ++(11)中实现类似集合类的.NET框架。我的问题是无效的协变类型。我有这些课程:

template<typename T>
class IEnumerator
{
public:
    virtual bool MoveNext() = 0;
    //...
};

template<typename T>
class IEnumerable
{
    virtual IEnumerator<T> GetEnumerator() = 0;
};

template<typename T>
class List : public IEnumerable<T>
{
public:
    struct Enumerator : public IEnumerator<T>
    {
        Enumerator(List<T> &list)
        {
            //...
        }
        // ...
    };

    Enumerator GetEnumerator()
    {
        return Enumerator(*this);
    }
};

据我说,这太棒了。但在C ++中实现它似乎是不可能的。我得到了g ++的“无效协变返回类型”,据我所知,问题是GetEnumerator可能只返回一个指针或对Enumerator的引用,而不是Enumerator本身的对象。

我想避免返回这样的指针:

Enumerator *GetEnumerator()
{
    return new Enumerator(*this);
}

因为我不希望调用者打扰删除。使用临时对象我确定该对象会被自动删除,因为它不再需要了。使用引用可能更糟糕。

我错过了什么吗?或者C ++标准(和语言)中是否存在巨大漏洞?我真的很想实现这样的目标。

提前致谢。

3 个答案:

答案 0 :(得分:5)

无法实现协变值返回类型。问题是调用者有责任在堆栈中为返回的对象分配空间,并且在编译时,协变值返回所需的空间量将是未知的。

这与指针/引用无缝协作,因为返回的对象是指针或引用(而不是实际的派生对象),并且在编译时已知大小。

在与@curiousguy讨论相当荒谬(在我身边)之后,我必须从之前的回答中回溯。没有技术问题会导致协变值返回类型无法实现。另一方面,它会产生不同的负面影响:

从设计角度来看,如果从base调用返回的对象,则必须切片(这是返回对象的大小很重要的地方)。这与当前模型明显不同,在当前模型中,函数始终返回相同的对象,它只是更改类型的引用或指针。但实际的对象是相同的。

在一般情况下,协变值类型会抑制某些复制省略优化。目前,对于按值返回的函数,许多调用约定规定调用者将指针传递给返回对象的位置。这允许调用者保留将保存该值的变量的空间,然后传递该指针。然后,被调用者可以使用该指针来构造代替将在调用者上下文中保存值的对象,并且不需要副本。使用协变值返回类型,并且必须销毁最终覆盖者创建的派生对象最多,以避免未定义的行为。调用者会将指针传递给内存中的某个位置,trampoline函数必须为最终覆盖的返回对象保留空间,然后需要将 slice-copy 从第二个对象传递给首先,要承担副本的费用。

无论如何,操作的实际成本不会像最终覆盖的调用的语义不同 * 取决于执行调用的引用的静态类型。


* 当前语言定义已经是这种情况。对于所有非虚函数,如果派生类型隐藏基础上的成员函数,则返回指针/引用的静态类型(这又取决于用于调用虚拟的静态类型) function)将影响实际调用的函数和行为的不同。

答案 1 :(得分:1)

template<typename T>
class IEnumerable
{
    virtual IEnumerator<T> GetEnumerator() = 0;
};

您正在尝试返回IEnumerable<T>,但它是一个抽象基类:这意味着您承诺构建一个无法实例化的类的对象!

只能实例化从抽象基类派生的具体类

您可能打算返回指向此类对象的指针。无论如何,这是糟糕的设计。您不需要在C ++中模拟Java。

答案 2 :(得分:0)

除非你使用指针,否则你不会在C ++中做类似的事情。 .net的人使用引用,所以它几乎是相同的东西。

在C ++中,您更可能使用概念而不是继承来实现它。您应该回顾“通用编程”的想法。 boost网站有一个不错的介绍:http://www.boost.org/community/generic_programming.html