【问题标题】:Is it possible to return a reference via an argument passed by reference?是否可以通过引用传递的参数返回引用?
【发布时间】:2019-07-31 16:24:50
【问题描述】:

我想从函数返回布尔值或成功/失败枚举并通过引用修改参数。但是,我想在调用函数中构造一个引用,而不是复制值。

我有一些容器(比如 std::queue 类型的“example_q”)。 queue.front() 将返回对存储在队列中的值的引用。我可以复制该引用(示例 A),或者我可以获取该引用的引用(示例 B),从而允许值保留在队列中,但可以在队列之外使用。

一)

int a = example_q.front();

B)

int& b = example_q.front();

使用这种差异,我还可以返回排队的值:

一)

int get_front()
{
    int a = example_q.front(); 
    return a;
}

B)

int& get_front()
{
    return example_q.front();
}

使用选项 'B' 我可以避免不必要的复制,而无需通过 std::move() 语义将数据移出队列。

我的问题是,我可以通过引用传递的参数执行“B”吗?我需要以某种方式使用 std::move()/rvalues/&& 吗?

void get_front(int& int_ref)
{
    // somehow don't copy the value into referenced int_ref, but construct 
    // a reference in the caller based on an input argument?
    int_ref = example_q.front(); 
}

这将解决的问题是使 API 匹配其他修改引用参数但返回成功/失败值的函数,即:

if(q.get_front(referrence_magic_here))
{
    ...
}

我可以颠倒顺序得到想要的结果,IE:

int& get_front(bool& success)
{
    ...
}

但我宁愿保留我的 API 的模式,并尽可能通过 if() 语句中的一行来完成。

可能是这样的:

bool get_front(int&& int_rvalue)
{
    ...
    int_rvalue = example_q.front();
    ...
    return true_or_false;
}


void calling_func()
{
    ...
    if(get_front(int& magical_ref))
    {
       ... //use magical_ref here?
    }
    ...
}

【问题讨论】:

  • 为什么不直接使用int& get_front() { return example_q.front(); }?输出参数通常被认为是一个坏主意。
  • 否,但您可以传递对指针的引用并修改指针以指向您的数据。更好的是,返回一个带有引用的元组以及您需要返回的任何其他内容:std::tuple<int&, bool> get_front()

标签: c++ reference rvalue


【解决方案1】:

不,你不能那样做。

除了在它的初始化器中,一个引用的行为就像它所引用的东西。通过将其作为函数参数传递,您可以将初始化程序“隐藏”在想要进行分配的部分中。因此,该函数无法访问事物的引用行为。

如果你想这样做,你将不得不使用指针:

void get_front(int*& int_ptr)
{
    int_ptr = &example_q.front(); 
}

int* ptr = nullptr;
get_front(ptr);

// optional:
int& ref = *ptr;

(Ew!)

选项 B 很好。

【讨论】:

    【解决方案2】:

    此代码是无效的 C++:

    if(get_front(int& magical_ref))
    

    您不能在将新变量传递给函数时声明它。而且因为引用变量必须同时声明和初始化,所以不可能通过将引用传递给函数来初始化引用。

    但是,您可以这样做:

    if(int &magical_ref = get_front()) {
    

    但请注意,您将检查 magical_ref 是否为 0,这与您在示例中的条件不同。

    如果您的逻辑就像比较int 一样简单,您可以这样做:

    if (int& magical_ref = get_front(); magical_ref == 42)
    

    【讨论】:

    • 这是有趣的一点,我在问题中做了一个简单的例子,但实际用例是从不能保证是完整的队列中获取 std::unique_ptr 的引用 XD。
    【解决方案3】:

    您可以返回std::tuple<int&, /* status condition */> 并检查状态。例如:

    std::tuple<int&, bool> get_front() {
        static int example = 0;
        return {example, false};
    }
    
    ...
    
    // C++17's structured bindings + if statement with initializer
    if (auto [ref, success] = get_front(); success) {
        ref = 42;
    }
    

    Demo

    【讨论】:

    • 这将是我推荐的多次退货解决方案,但由于向后兼容性问题,我目前有 C++11 的自我限制
    猜你喜欢
    • 1970-01-01
    • 2013-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-21
    • 2018-07-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多