簡體   English   中英

通過引用傳遞 function object 在 std::generate_n() 中不起作用

[英]Passing function object by reference doesn't work in std::generate_n()

我制作了一個用於 std::generate_n 的 FibonacciSeries 仿函數。 但它並沒有按應有的方式工作。 通過引用傳遞函子效果不佳。

在以下程序中 0 1 1 2 3 5 8 13 是預期的 output 但我得到 0 1 1 2 0 1 1 2 作為 output。 有什么問題?

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

inline void printvec(const vector<int>& vec)
{
    for (const auto& v : vec)
        cout << v << ' ';
    cout << endl;
}


class FibonacciSeries
{
private:
    int f1;
    int f2;
    int f3;
public:
    FibonacciSeries() :f1(0), f2(1) {}
    int operator() () {    
        f3 = f1 + f2;
        int  result = f1;
        f1 = f2;
        f2 = f3;
        return result;
    }
    void printstat(){
        cout << f1 << endl;
    }
};

int main()
{
    vector<int> vec;
    FibonacciSeries series;
    //passing function object by reference
    generate_n<back_insert_iterator<vector<int>>, 
        int, FibonacciSeries&>(back_inserter(vec), 4, series);

    printvec(vec);// prints 0 1 1 2

    series.printstat();//prints 0//unexpected
    
    //passing function object by value
    generate_n(back_inserter(vec), 4, series);
    printvec(vec);//prints 0 1 1 2 0 1 1 2//unexpected
}

我無法重現 gcc 主干( https://godbolt.org/z/PfPPE67h8 )的問題。 但是,標准算法可能會復制內部傳遞給它們的函子。 不確定實現中實際發生了什么“錯誤”,但假設算法以

  std::remove_reference<Generator> g = generator;

並使用它來生成 output。 必須閱讀實現以查看導致您的 output 的原因。 但是,使用FibonacciSeries&作為顯式模板參數是錯誤的方法。 即使生成器是通過引用傳遞的,它也可以在內部復制。

避免您現在觀察到的此類問題的最簡單方法是不要依賴具有 state 的仿函數。 與其讓 state 成為函子的成員,不如讓它通過引用捕獲 state 並將 state 存儲在其他地方。 正如 Sam 在評論中所建議的那樣,使用 Lamba,或者編寫您的自定義包裝器:

struct FibonacciSeriesWrapper {
    FibonacciSeries& parent;
    int operator() () { return parent(); }
};

int main()
{
    vector<int> vec;
    FibonacciSeries series;    
    //passing function object by reference
    generate_n(back_inserter(vec), 4, FibonacciSeriesWrapper{series});
    generate_n(back_inserter(vec), 4, FibonacciSeriesWrapper{series});
    printvec(vec);//prints 0 1 1 2 3 5 8 13
}

現場演示

您的生成器( FibonnachiSeries對象)被復制到std::generate_n調用。 所以原廠 object state 不變。 一種解決方法可能是通過 lambda

generate_n(back_inserter(vec), 4, 
           [&series] { return series(); });

// UPD:沒關系,將FibonacchiSeries聲明為參考應該會有所幫助。 你的版本對我來說很好。 你用什么編譯器?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM