[英]"Pimp my Library" in C++
在 Scala 中,有一種設計模式通常稱為“pimp my library”。 基本思想是我們有一些 class Foo
(大概在一些我們無法修改的庫中),我們希望Foo
表現得像它有一些方法或行為frobnicate
,我們可以使用隱式 class 在之后添加方法事實。
implicit class Bar(val foo: Foo) extends AnyVal {
def frobnicate(): Unit = {
// Something really cool happens here ...
}
}
然后,如果我們有一個Foo
的實例,我們可以在它上面調用frobnicate
,只要Bar
在 scope 中,Scala 編譯器就會足夠聰明,可以將Foo
隱式轉換為Bar
。
val foo = new Foo()
foo.frobnicate() // Correctly calls new Bar(foo).frobnicate()
我想在 C++ 中做同樣的事情。 我知道 C++ 具有隱式強制轉換,但在訪問成員時它們似乎不會觸發。 舉個具體的例子,C++ 中的以下代碼會產生錯誤。
class Foo {}; // Assume we can't modify this class Foo
class Bar {
private:
Foo foo;
public:
Bar(Foo foo) : foo(foo) {}
void frobnicate() {
cout << "Frobnicating :)" << endl;
}
};
void frobnicate(Bar bar) {
cout << "Frobnicating :)" << endl;
}
int main() {
Foo value;
frobnicate(value); // This works
value.frobnicate(); // But this doesn't
return 0;
}
在value.frobnicate()
行上, C++ 似乎沒有在該上下文中尋找隱式轉換。
main.cc:30:9:錯誤:“類 Foo”沒有名為“frobnicate”的成員
注意:我現在正在使用 C++11 進行編譯。 粗略地看一下較新的 C++ 版本,從那時起似乎沒有任何會影響這個問題的東西發生變化。 C++11 兼容的解決方案是理想的,但在較新的 C++ 版本中執行此操作的方法也很好,用於教學目的。
您所描述的內容稱為U nified F unction C all S yntax(UFCS),並且目前無法在C ++中完成。 任何使用D中的范圍和算法鏈接的人都可以證明這將是多么令人驚奇。
缺乏UFCS支持實際上是為什么一般的現代智慧是使用自由浮動函數和ADL用於不需要虛擬或封裝的任何東西的主要原因之一。
有提議將D的UFCS引入該語言,但它仍然只是一個提議:
https://isocpp.org/files/papers/N4165.pdf
編輯:對於想知道為什么我們想要這個功能的人,想象能夠編寫以下內容:
std::vector<int> foo(const std::vector<int>& v) {
return v.filter([](int x) {return x > 5;})
.map([](int x) {return x*x;})
.sort();
}
雖然你不能完全按照你的要求去做,但你可以繼承Foo
並擴展它。
class Bar : public Foo{
public:
void frobnicate() {
cout << "Frobnicating :)" << endl;
}
}
現在Bar
擁有Foo
所擁有的一切以及新方法。 見http://www.cplusplus.com/doc/tutorial/inheritance/
C ++似乎沒有在該上下文中尋找隱式轉換。
那是正確的。 您正在尋找的機制在語言中不存在。
不完全是,但是...
#include <iostream>
class Foo
{
public:
void nothingUpMySleeve()
{
std::cout << "Foo!\n";
}
};
class Bar
{
private:
Foo & foo;
public:
Bar(Foo & foo) : foo { foo }
{
}
void frobnicate()
{
std::cout << "Frobnicating\n";
}
Foo * operator ->()
{
return &this->foo;
}
operator Foo &()
{
return this->foo;
}
};
void thisFunctionOnlyAcceptsFoo(Foo & foo)
{
std::cout << "Yes, that's a Foo\n";
}
void useExtendedType(Bar wrapper)
{
// Use the extension function
wrapper.frobnicate();
// Use arrow notation to use the original functions
wrapper->nothingUpMySleeve();
// Implicit conversion kicks in when necessary
thisFunctionOnlyAcceptsFoo(wrapper);
}
int main()
{
Foo value;
// Pass to a function that uses Bar
useExtendedType(value);
}
我真的不建議在實際代碼中這樣做。 這只是一個便宜的派對把戲。
甚至不清楚Bar
是否應該擁有Foo
的副本或只是引用它。 我選擇僅引用是因為我假設其他一些代碼正在管理Foo
的生命周期,這樣可以非常便宜地創建和銷毀Bar
。 您只需要注意Bar
的壽命總是比Foo
的壽命短,否則恐怕是鼻惡魔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.