[英]C++11 / lambda functions & function pointers
好吧,也許我的問題有些人為的。
我試圖找到一種優雅的解決方案,以便每次我想修改只能通過const Getter和non const Setter訪問的對象的一部分時,減少以下樣板代碼。
Content c = container.GetContent();
c.SetX(3);
container.SetContent(c);
我知道我可以有一個非常量獲取器,但是我暫時想堅持使用它。
因此,我嘗試使用lambdas,目前有以下實現:
#include <iostream>
class Content
{
public:
Content(int x) :mX(x) {}
const int GetX() const
{
return mX;
}
void SetX(const int &x)
{
mX = x;
}
private:
int mX;
};
//for clarity ContentFunctionChanger is a typedef for any function of type : void f(Content &)
typedef void (*ContentFunctionChanger)(Content &);
class Container
{
public:
Container(const Content &c) :mContent(c) {}
const Content & GetContent() const
{
return mContent;
}
void SetContent(const Content &c)
{
mContent = c;
}
void ChangeContent(ContentFunctionChanger &function)
{
(*function)(mContent);
}
private:
Content mContent;
};
int main()
{
Content content(1);
Container container(content);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
{
//Classic method using Get() then Set()
Content c = container.GetContent();
c.SetX(3);
container.SetContent(c);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
{
//Method 1 : with a named lambda function whose type is written at the declaration
//It works, but it is not concise
ContentFunctionChanger func = [] (Content & c) { c.SetX(5); };
container.ChangeContent(func);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
/*
{
//Method 2 : with a named lambda function whose type is not written (using auto)
//It will not compile...
auto func = [] (Content & c) { c.SetX(7); };
container.ChangeContent(func);
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
{
//Method 3: with an anonmymous lambda.
//Concise enough, but it does not compile either...
container.ChangeContent([] (Content & c) { c.SetX(9); } );
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
*/
return 0;
}
我的問題是方法2和方法3更簡潔,但無法編譯。 我想知道是否有希望使它們編譯。
有人可以幫忙嗎?
您的問題是您嘗試傳遞一個臨時對象作為引用:從此聲明中刪除&
,它將起作用:
void ChangeContent(ContentFunctionChanger &function)
(嗯,您還需要將func2
重命名為一個地方的func
)。 無論如何,通過引用傳遞函數指針實際上並沒有任何意義。 這樣做只會增加另一個間接作用而沒有任何好處,而不必要的間接作用只會浪費時間。
只是為了說明臨時信息的來源:lambda表達式的類型是每個lambda表達式的唯一類型。 如果lambda函數的捕獲為空,則可以將其轉換為函數指針。 在您的第一個代碼中,您明確地進行了此轉換,產生了一個可以綁定到引用的左值。 在其他兩種情況下,您依賴於隱式轉換,該轉換產生的收益率和rvalue不能綁定到非const
引用(也就是說,您可以通過在&
前面添加const
來解決此問題,但額外的間接尋址是仍然毫無意義)。
您可以使用模板啟用方法3:
template<typename F>
void ChangeContent(F function)
{
function(mContent);
}
這樣您就可以傳遞任何可調用的內容(例如,函子)。
另一種(C ++ 03)方法是為Set
方法實現流利的接口:
// kind of a functional set — if we want Set to constant, we need to return a new object
Content SetX(const int &x) const
{
Content ret = *this;
ret.mX = x;
return ret;
}
並按如下所示使用它:
{
//Fluent interface
container.SetContent( container.GetContent().SetX(111) );
std::cout << "x=" << container.GetContent().GetX() << std::endl;
}
朝完全不同的方向前進,讓SetX返回對該對象的引用,然后可以鏈接參數:
Content & SetX(const int &x)
{
mX = x;
return * this ;
}
...
container.SetContent( container.GetContent().setX( 3)) ;
但是,在這種特殊情況下, container.GetContent()
返回一個const
因此您甚至無法對其調用setX,這引出了一個問題,即如果必須創建一個新的對象來對其進行修改,為什么還要費心地調用GetContent()
。
盡管其他人已經修改了setX
的行為以返回一個新對象,但我認為這不適合該動詞。 我希望set*
修改一個對象,而不返回一個新對象。 因此,這就是我如何解決保留setX
的含義並處理來自getter的const
值的問題。
在不復制Content
的簡單情況下,只需新建一個:
container.SetContent( Content( 3)) ;
或者,在更復雜的狀態下,有一些有價值的狀態,則拋出一個臨時對象:
container.SetContent( Content( container.getContent()).setX( 3) ) ;
值得慶幸的是,我認為吸氣劑/定阻劑的趨勢正在下降。
下面是使用Barmaley.exe建議的更正代碼。
我們越來越接近具有類似於C#屬性的行為,因為類似
container.ChangeContent([] (Content & c) { c.SetX(9); } );
可以調用非平凡的設置器(例如,它將更改對象修改日期)
完整代碼如下:
#include <iostream>
class Content
{
public:
Content(int x) :mX(x) {}
const int GetX() const
{
return mX;
}
void SetX(const int &x)
{
mX = x;
}
private:
int mX;
};
class Container
{
public:
Container(const Content &c) :mContent(c), mWasUpdated(false) {}
const Content & GetContent() const
{
return mContent;
}
void SetContent(const Content &c)
{
mContent = c;
mWasUpdated = true; //dummy example of a non trivial setter
}
bool WasUpdated() const
{
return mWasUpdated;
}
//FnContentChanger can be a function, a functor, any callable that modifies Content...
//We are getting closer to having a behaviour that resemble C# properties
template<typename FnContentChanger>
void ChangeContent(FnContentChanger function)
{
Content c = GetContent();
function(c);
SetContent(c);
}
private:
bool mWasUpdated;
Content mContent;
};
int main()
{
{
//Classic method using Get() then Set()
Content content(1);
Container container(content);
std::cout << "x=" << container.GetContent().GetX() << " wasUpdated=" << container.WasUpdated() << std::endl;
Content c = container.GetContent();
c.SetX(3);
container.SetContent(c);
std::cout << "x=" << container.GetContent().GetX() << " wasUpdated=" << container.WasUpdated() << std::endl;
}
{
//Method 2: with an anonmymous lambda.
Content content(1);
Container container(content);
std::cout << "x=" << container.GetContent().GetX() << " wasUpdated=" << container.WasUpdated() << std::endl;
container.ChangeContent([] (Content & c) { c.SetX(9); } );
std::cout << "x=" << container.GetContent().GetX() << " wasUpdated=" << container.WasUpdated() << std::endl;
}
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.