在 C++20 中删除协程的复制/移动函数并实例化它是否合法?

破碎机

我注意到以下代码都被MSVC 和 GCC接受(下面是缩短的 TLDR 版本):

template<typename T>
struct Generator {
    struct promise_type {
        std::suspend_always initial_suspend() {
            return {};
        }
        std::suspend_always final_suspend() noexcept {
            return {};
        }
        auto get_return_object() {
            return Generator{ std::coroutine_handle<promise_type>::from_promise(*this) };
        }

        std::suspend_always yield_value(T value) {
            current_value = value;
            return {};
        }
        void return_void() {}
        void unhandled_exception() {
            std::exit(1);
        }

        T current_value;
    };
    
    Generator(std::coroutine_handle<promise_type> h): coro(h) {}                

    std::coroutine_handle<promise_type> coro;
    
    ~Generator() {
        if (coro) coro.destroy();
    }
    Generator(const Generator&)              = delete;
    Generator& operator = (const Generator&) = delete;
    Generator(Generator&&)                   = delete;
    Generator& operator = (Generator&&)      = delete;

    T operator()() {
        coro.resume();
        return coro.promise().current_value;
    }

};

Generator<int> getNext() {
    int value = 0;
    while (true) {
        co_yield value;
        value++;
    }
}

int main() {
    Generator<int> gen = getNext();
    for (int i = 0; i <= 2; ++i) {
        int val = gen();
        std::cout << "val: " << val << std::endl;
    }
    
}

TLDR 版本:

template<typename T>
struct Generator {
    struct promise_type {
        //...
    };
    
    //...
    
    Generator(const Generator&)              = delete;
    Generator& operator = (const Generator&) = delete;
    Generator(Generator&&)                   = delete;
    Generator& operator = (Generator&&)      = delete;

    //...

};

Generator<int> getNext() {
    //...
}

int main() {
    Generator<int> gen = getNext();
    //...
}

但是,我想知道 C++20 标准是否允许这样做。通常,如果删除复制和移动函数,则函数无法检索类型:

struct MyType
{
    MyType() {}

    MyType(const MyType&)              = delete;
    MyType& operator = (const MyType&) = delete;
    MyType(MyType&&)                   = delete;
    MyType& operator = (MyType&&)      = delete;
};

MyType generateType()
{
    MyType val;
    return val; // <--- Compile Error
}

乍一看,这一行似乎也使用了已删除的函数: Generator<int> gen = getNext();

协程允许这样做吗?如果是,标准的哪一部分允许?

马蒂亚斯·格林

我相信该Generator对象是通过调用来检索的get_return_object(),它返回一个纯右值。从 C++17 开始,这需要强制复制省略。参见 cppreference.com:

在以下情况下,编译器需要省略类对象的复制和移动构造,即使复制/移动构造函数和析构函数具有可观察到的副作用。对象被直接构建到存储中,否则它们将被复制/移动到那里。复制/移动构造函数不需要存在或可访问:

在 return 语句中,当操作数是与函数返回类型相同类类型(忽略 cv 限定)的纯右值时:

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章