C ++根据条件通过复制或使用引用进行初始化

C++ Initialization by making a copy or using reference depending on the condition

І 有一个名为 do_copybool 变量。

如果do_copy == true,我想用副本工作,比如
some_type model = input_model

如果do_copy == false,我想使用参考,比如
some_type& model = input_model

满足我要求的代码:

some_type copy_model;
if (do_copy)
    copy_model = input_model;
some_type& model = do_copy ? copy_model : input_model;

看起来不太好,我调用了默认构造函数,do_copy == false不需要。

有没有办法让它更优雅?

避免不必要的构造函数的一种方法是仅在需要时动态分配 copy_model

std::unique_ptr<some_type> copy_model;
if (do_copy)
    copy_model = std::make_unique<some_type>(input_model);
some_type& model = copy_model ? *copy_model : input_model;

虽然我不确定这样更优雅。

将使用 model 的逻辑移动到一个单独的函数中:

void doSomething(some_type& model)
{
    //...
}

...

if (do_copy)
{
    some_type copy_model = input_model;
    doSomething(copy_model);
}
else
    doSomething(input_model);

Demo

或者,在 C++11 及更高版本中:

template<typename T>
void doSomething(T&& model) // T will be lvalue-ref or rvalue-ref depending on input
{
    //...
}

...

if (do_copy)
    doSomething(some_type{input_model});
else
    doSomething(input_model);

Demo

您可以将副本作为三元表达式的一部分:

some_type copy_model;
some_type& model =
    do_copy
    ? (copy_model = input_model, copy_model)
    : (input_model);

这仍然需要默认构造 copy_model 即使 do_copy 为 false。如果你的默认构造函数真的很昂贵,你可以使用一个可选的:

std::optional<some_type> copy_model;
some_type& model =
    do_copy
    ? (copy_model = input_model, *copy_model)
    : (input_model);

请注意,这并不是完全免费的:与 some_type 相比,std::optional<some_type> 的析构函数有一个额外的分支。

如果您发现自己经常需要这样做,为什么不将此模式包装在 class:

template<class T>
struct copy_or_reference
{
    std::optional<T> maybeCopy;
    T& ref;

    copy_or_reference(copy_tag, T& x)
        : ref(x)
    {};

    copy_or_reference(reference_tag, const T& x)
        : maybeCopy(x), ref(*maybeCopy)
    {};

    operator T& () const { return ref; };
    operator T& () { return ref; };
};

template<class T>
auto make_copy_or_reference(bool copy, T& x)
{
    return copy ? copy_or_reference<T>(copy_tag{}, x) : copy_or_reference<T>(reference_tag{}, x);
}


void do_something(some_type&);

void do_something_else()
{
    ...
    copy_or_reference<some_type> model = make_copy_or_reference(do_copy, input_model);
    do_something(model);
}