简体   繁体   English

如何用std :: variant保证复制省略?

[英]How to guarantee copy elision with std::variant?

I have this type: 我有这种类型:

struct immobile {
   // other stuff omitted
   immobile(immobile&) = delete;
   immobile(immobile&&) = delete;
};
immobile mk_immobile();
// e.g. this compiles
// mk_immobile() is a prvalue and i is its result object
immobile i(mk_immobile());

I also have this class template: 我也有这个类模板:

template<typename T>
struct container {
    std::variant<T, other_stuff> var;
    template<typename... Args>
    container(Args&&... args)
    : var(std::in_place_index<0>, std::forward<Args>(args)...) {}
};

I want to construct a container around the object produced by mk_immobile() , with the immobile object used to initialize one of the variants of var . 我想建立一个container周围所产生的对象mk_immobile()immobile用于初始化的变体的一个目的var

container<immobile> c(mk_immobile());

However, this does not work. 但是,这不起作用。 For one, std::variant 's constructor wants std::is_constructible_v<immobile, immobile> , which doesn't hold. 首先, std::variant的构造函数需要std::is_constructible_v<immobile, immobile> ,它不成立。 Worse, even this simplified version fails: 更糟糕的是,即使这个简化版本也失败了

template<typename T>
struct demonstration {
    T t;
    template<typename... Args>
    demonstration(Args&&... args) : t(std::forward<Args>(args)...) {}
};
demonstration<immobile> d(mk_immobile());

Which seems to imply that std::forward does not, in fact, perfectly forward—prvalues do not forward as prvalues. 这似乎暗示std::forward实际上并不是完美的前锋 - prvalues不会作为prvalues前进。 (This makes sense to me; I don't think doing that would be possible.) I can make demonstration work by changing it to this: (这对我来说很有意义;我不认为这样做是可能的。)我可以通过改变它来进行demonstration工作:

template<typename T>
struct demonstration {
    T t;
    template<typename F>
    demonstration(F&& f) : t(std::forward<F>(f)()) {}
};
demonstration<immobile> d([] { return mk_immobile(); });

But I do not see a way to change container in a similar manner. 但我没有看到以类似方式更换container的方法。 How do I change container so that it can construct a std::variant (or other tagged union) out of a prvalue? 如何更改container以便它可以从prvalue构造一个std::variant (或其他标记的联合)? I can change container but cannot change immobile . 我可以更换container但不能改变immobile

You abuse casts 你滥用演员

template<typename F>
struct initializer
{
    F f;
    template<typename T>
    operator T()
    {
        return f();
    }
};

template<typename F>
initializer(F&&) -> initializer<F>;

And use as 并用作

container<immobile> c{initializer{[]{
    return mk_immobile();
}}};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM