协变返回类型与非指针/引用返回类型 [英] Covariant return type with non-pointer/reference return type

查看:103
本文介绍了协变返回类型与非指针/引用返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在C ++(11)中实现一个.NET框架,例如collection类.我的问题是无效的协变类型.我有这些课:

I'm trying to implement a .NET framework like collection class in C++(11). My problem is an invalid covariant type. I have these classes:

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本身的对象.

According to me, this is awesome. But it looks impossible to implement it in C++. I get the "Invalid covariant return type" by g++, and as far as I read, the problem is that GetEnumerator might only return a pointer or a reference to Enumerator, and not an object of Enumerator itself.

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

I'd like to avoid returning a pointer like this:

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

因为我不希望呼叫者费心删除.使用临时对象,我将确保该对象被自动删除,因为不再需要该对象.使用引用可能会更糟.

because I don't want the caller to bother deleting. Using the temporary object I'd be sure that the object is deleted automatically as it isn't needed anymore. Using references might be even worse.

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

Am I missing something? Or is there a huge hole in the C++ standard (and language)? I'd really like to achieve something like this.

提前谢谢.

推荐答案

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

Covariant value return types cannot be implemented. The problem is that it is the responsibility of the caller to allocate space in the stack for the returned object and the amount of space required for a covariant value return would be unknown at compile time.

这与指针/引用无缝配合,因为返回的对象是指针或引用(而不是实际的派生对象),并且大小在编译时就知道了.

This works seamlessly with pointers/references as the returned object is the pointer or reference (rather than the actual derived object), and the size is known at compile time.

在与@curiousguy进行相当荒谬的(在我这边)讨论之后,我必须回溯上一个答案.没有技术问题会导致协变量值返回类型成为不可能.另一方面,它会有不同的负面影响:

After a rather absurd (on my side) discussion with @curiousguy I must backtrack from the previous answer. There is not technical issue that would make covariant value return types impossible. On the other hand, it would have different negative effects:

从设计的角度来看,如果从基础调用返回的对象,则必须将其切片(在此处,返回的对象的大小很重要).这与当前模型有明显区别,在当前模型中,函数始终返回 same 对象,只有引用或指针会更改类型.但是实际的 object 是相同的.

From a design perspective, the returned object would have to be sliced if called from base (this is where the size of the returned object matters). This is a clear difference from the current model, in the current model the function always returns the same object, it is only the reference or pointer that changes types. But the actual object is the same.

在一般情况下,协变值类型会抑制某些复制删除优化.当前,对于按值返回的函数,许多调用约定规定调用者将指针传递给返回对象的位置.这样,调用方就可以保留将保留该值的变量的空间,然后将其传递给指针.然后,被调用方可以使用该指针来代替将在调用方上下文中保存该值的对象的构造,并且不需要任何副本.具有协变量值的返回类型,并且由于必须破坏最终重写器创建的最派生对象,以避免未定义的行为.调用者将指针传递到内存中的某个位置,蹦床函数将不得不为最终重写器的返回对象保留空间,然后它需要从第二个对象 slice-copy 到首先,要承担复制费用.

In the general case, covariant value types would inhibit some of the copy-elision optimizations. Currently, many calling conventions, for a function that returns by value, dictate that the caller passes a pointer to the location of the returned object. That allows the caller to reserve the space of the variable that will hold the value, and then pass that pointer on. The callee can then use that pointer to construct in place of the object that will hold the value in the caller context and no copies will be required. With covariant value returned types and because the most derived object created by the final overrider must be destroyed to avoid undefined behavior. The caller would pass a pointer to a location in memory, the trampoline function would have to reserve space for the returned object of the final overrider, then it would need to slice-copy from that second object to the first, incurring the cost of a copy.

无论如何,操作的实际 cost 不会成为问题,因为最终的替代程序的调用语义会有所不同 * 取决于调用通过其引用的静态类型.

At any rate, the actual cost of the operation would not be as much of an issue as the fact that the semantics of the call to the final overrider would be different* depending on what the static type of the reference through which the call is performed.

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

* This is already the case with the current language definition. For all non-virtual functions, if the derived type hides a member function on the base, then the static type of the returned pointer/reference (which in turn depends on the static type used to call the virtual function) will affect what function gets actually called and the behavior differs.

这篇关于协变返回类型与非指针/引用返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆