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

HTN*_*TNW 6 c++ variant copy-elision c++17

我有这种类型:

\n\n
struct immobile {\n   // other stuff omitted\n   immobile(immobile&) = delete;\n   immobile(immobile&&) = delete;\n};\nimmobile mk_immobile();\n// e.g. this compiles\n// mk_immobile() is a prvalue and i is its result object\nimmobile i(mk_immobile());\n
Run Code Online (Sandbox Code Playgroud)\n\n

我也有这个类模板:

\n\n
template<typename T>\nstruct container {\n    std::variant<T, other_stuff> var;\n    template<typename... Args>\n    container(Args&&... args)\n    : var(std::in_place_index<0>, std::forward<Args>(args)...) {}\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

我想container围绕 生成的对象构造mk_immobile(),该immobile对象用于初始化 的变体之一var

\n\n
container<immobile> c(mk_immobile());\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,这是行不通的。其一,std::variant的构造函数要求std::is_constructible_v<immobile, immobile>,但它不成立。更糟糕的是,即使这个简化版本也失败了:

\n\n
template<typename T>\nstruct demonstration {\n    T t;\n    template<typename... Args>\n    demonstration(Args&&... args) : t(std::forward<Args>(args)...) {}\n};\ndemonstration<immobile> d(mk_immobile());\n
Run Code Online (Sandbox Code Playgroud)\n\n

这似乎意味着std::forward实际上并没有完全转发\xe2\x80\x94prvalues 不会作为纯右值转发。(这对我来说很有意义;我认为这样做是不可能的。)我可以demonstration通过将其更改为这样来完成工作:

\n\n
template<typename T>\nstruct demonstration {\n    T t;\n    template<typename F>\n    demonstration(F&& f) : t(std::forward<F>(f)()) {}\n};\ndemonstration<immobile> d([] { return mk_immobile(); });\n
Run Code Online (Sandbox Code Playgroud)\n\n

但我看不出有什么办法可以container以类似的方式进行改变。我如何进行更改,container以便它可以std::variant从纯右值构造一个(或其他标记的联合)?我可以改变container,却无法改变immobile

\n

Pas*_* By 6

你滥用演员表

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

template<typename F>
initializer(F&&) -> initializer<F>;
Run Code Online (Sandbox Code Playgroud)

并用作

container<immobile> c{initializer{[]{
    return mk_immobile();
}}};
Run Code Online (Sandbox Code Playgroud)