2015-06-10 27 views
7

Şu ana kadar fonksiyon göstergelerini kullanıyorum, C++ formatında bu formatta. Şimdi ve sonra bazı kullanımları var ve merak ediyorum C++ 11/14 kendi alternatif olarak tanıtılan başka bir şey var. Modern C++ alternatifi fonksiyon işaretçilerine

#include <iostream> 
using namespace std; 

void sayHello(); 
void someFunction(void f()); 

int main() { 

    someFunction(sayHello); 
    return 0; 
} 
void sayHello(){ 
    std::cout<<"\n Hello World"; 
} 
void someFunction(void f()){ 
    f(); 
} 

Bu question bakmak yaptım ama işlev işaretçileri geleneksel kullanımı üzerinde hiçbir avantaj anlayamadık. Ayrıca, ben hiç kimseyi kullanmayan birini görmediğimden beri, fonksiyon işaretçileri kullanarak yanlış bir şey (tavsiye edilmez) olayı sormak istiyorum. Veya başka bir alternatif hediye.

+0

mümkün yinelenen [I Std :: işlevi veya C++ bir işlev işaretçisi kullanımı mı?] (http://stackoverflow.com/questions/25848690/should-i-use-stdfunction-or-a-function-pointer -in-c) –

+0

deneyin lambda'lar yerine :) –

+0

@AndrewLavq, ben lambdas okunabilirlikle karmaşa kullanıyorum eğer bazı ağır baskı fonksiyonları (olmasa da bir uygulama, sadece demo amaçlı) vardır. –

cevap

2

Ayrıca ben sormak istiyorum, (önerilmez) yanlış bir şey kimsenin onları kullanarak görmek asla beri fonksiyon işaretçileri kullanarak şey yoktur.

Evet. Fonksiyon işaretçileri korkunç, korkunç şeyler. Öncelikle, jenerik olmayı desteklemiyorlar - bu nedenle, T için std::vector<T> alan bir işlev işaretçisi alamıyorsunuz. İkincisi, bağlı devlete sahip olmayı desteklemiyorlar, bu yüzden gelecekte herhangi bir zamanda, başka bir ülkeye başvurmak isteyen herkes, tamamen harap oluyorlar. Bu, üye işlevleri için this içerdiğinden özellikle kötüdür.

C++ 11'de işlev almak için iki yaklaşım vardır. Birincisi bir şablon kullanmaktır. İkincisi std :: işlevini kullanmaktır.

şablon tür şuna benzer:

burada
template<typename T> void func(F f) { 
    f(); 
} 

başlıca avantajı fonksiyon pointer, lambda, funktor dahil, fonksiyon herhangi bir nesne kabul ettiğini vardır, cilt-sonuç ne olursa olsun, ve F olabilir Şablonlar dahil olmak üzere herhangi bir imza ile herhangi bir sayıda işlev çağrısı aşırı yükü ve herhangi bir bağlı durum ile herhangi bir boyutta olabilir. Yani süper esnek esnek. Ayrıca, derleyici operatörü satır içi ve nesneyi doğrudan nesneye geçirebildiğinden maksimum derecede verimlidir.

int main() { 
    int x = 5; 
    func([=] { std::cout << x; }); 
} 

burada Ana olumsuz sanal fonksiyonlar için çalışmaz templates- olağan olumsuzlukları ve Başlıkta tanımlanmış olması gerekir. Diğer bir yaklaşım ise std::function'dir. std::function, aynı avantajların çoğuna sahiptir - herhangi bir boyutta olabilir, herhangi bir duruma bağlanabilir, ve herhangi bir şekilde callable olabilir, ancak bir kaç işlem gerçekleştirir.Esas olarak, imza türü tanımı anda sabittir, bu nedenle birkaç T henüz-to-bilinmelidir için std::function<void(std::vector<T>)> olamaz ve ayrıca katılan bazı dinamik indirection/ayırma (Eğer SBO yapamazsan) olabilir. Bunun avantajı std::function gerçek beton türü olduğundan, başka bir nesneyle olarak dolaştır olmasıdır, bu yüzden sanal bir işlev parametresi ve böyle şeyler olarak kullanılabilir.

Temel olarak, işlev işaretçileri inanılmaz derecede sınırlıdır ve gerçekten 'u ilginç bir şey yapamaz ve API'yı inanılmaz derecede esnek yapamaz. Onların iğrenç sözdizimi okyanusta bir işemek ve bir şablon takma ad ile onu azaltmak çok komik ama anlamsız. arasında

10

Sözünü ettiğiniz soru, std :: işlevini önerir, ancak std :: bind ile birleştirildiğinde değerini vurgulamaz (veya bunlardan bahseder).

Sizin örnek mümkün olan en basit olmakla birlikte, bir

std::function<void (int, int)> f ; 

bir işlev işaretçisi aşağı yukarı aynı şeyler yapabilirsiniz olduğunu varsayalım.

std::function<void(int)> g = std::bind(f, _1, 0) ; 
+0

Bu umut verici görünüyor, ama kafam karıştı, neden başka bir g fonksiyonunu f'den daha az parametresiyle kullanırdım? Başka bir deyişle, std :: bd ile std :: function için olası bir pratik kullanım durumu ne olurdu? –

+3

@hg_git: 'a' karşılaştırma (dize, dize, bool CaseSensitive) sahip olduğunu varsayalım. Büyük/küçük harf duyarlı olmayan bir karşılaştırma istediğinizde std :: bind (karşılaştır, _1, _2, false) öğesini geçmek isteyebilirsiniz. – MSalters

+1

@hg_git Eğer gecikmeli parametrelere sahip fonksiyonlar istiyorsanız. "Yapılacaklar" listesinin bir listesini tutan bir çalışan iş parçacığı düşünün. Ve çok yaygın: "geri alma listesi" ile bir uygulama. Her bir kullanıcı adımı kaydedilecek ve işlev çağrıları dahil edilen parametreler içeren bir listeye eklenecektir (bağlama). Geri almak isterseniz, listeyi geriye doğru çağırıp işlevin tersini yapın. – Klaus

3

: Ama bunu yapabilirsiniz std :: fonksiyonu ile, çok yapamaz işlev işaretçileri ile 0'a bağlı ikinci parametre ile f bir fonksiyon g (int) ihtiyaç olduğunu varsayalım Bu soruya bir göz attım ama geleneksel fonksiyon göstergelerine göre avantajlarını anlayamadım. Ayrıca ben sormak istiyorum, ben hiç kimseyi kullanmayan birini görmedim beri fonksiyon işaretçileri kullanarak ile yanlış bir şey (önerilmez) şey var mı.

  • Normal "küresel" işlevleri tipik/devlet olmaz yoktur. Fonksiyonel programlama paradigmasında geçiş sırasında devlete sahip olmak iyi olmasa da, bazen durum değişmiş olana ortogonal olarak bağlandığında kullanışlı olabilir (örnek olarak buluşsal). Burada, traktörler (veya fonksiyon nesneleri) avantajlıdır.

  • Normal fonksiyonlar (alt düzey işlevlerin üst düzey fonksiyonlarını oluşturarak çok iyi beste yok.

  • Normal fonksiyonları anında ek parametreler bağlanma için izin vermez.

  • Bazen normal fonksiyonlarını bağlamına bağlı olarak lambdas yerine ve vize versa olarak hareket edebilir.Çoğunlukla özel bir işlev yazmak istemezsiniz çünkü "konteyner traversal" sırasında çok yerel/özel gereksiniminiz vardır.

3

Geleneksel işlev göstergelerine bir alternatif olarak, template alias'u tanıtan C++ 11, variadic templates ile birlikte işlev işaretçisi sintaks'ı basitleştirebilir.Aşağıda, bir "şablon" fonksiyonu işaretçisi oluşturmak için bir örnek:

template <typename R, typename ...ARGS> using function = R(*)(ARGS...); 
Bu şekilde kullanılabilir

: Ayrıca

void foo()    { ... } 
int bar(int)    { ... } 
double baz(double, float) { ... } 

int main() 
{ 
    function<void>     f1 = foo; 
    function<int, int>    f2 = bar; 
    function<double, double, float> f3 = baz; 

    f1(); f2({}); f3({}, {}); 
    return 0; 
} 

, bu fonksiyon aşırı ile düzgünce başa çıkabilirim:

void overloaded(int)  { std::cout << "int version\n"; } 
void overloaded(double) { std::cout << "double version\n"; } 

int main() 
{ 
    function<void, int> f4 = overloaded; 
    function<void, double> f5 = overloaded; 

    f4({}); // int version 
    f5({}); // double version 
    return 0; 
} 

Ve işlev-işaretçileri parametreleri ilan etmek çok zarif bir yolu olarak kullanılabilir:

void callCallback(function<int, int> callback, int value) 
{ 
    std::cout << "Calling\n"; 
    std::cout << "v: " << callback(value) << '\n'; 
    std::cout << "Called\n"; 
} 

int main() 
{ 
    function<int, int> f2 = bar; 
    callCallback(f2, {}); 
    return 0; 
} 

Bu şablon diğer adı, std::function alternatifinin yanı sıra sakıncaları ve avantajları da bulunmuyor (good explanation here). Bir kısa olarak Live demo

, ben variadic şablonları ile kombine şablon takma çiğ işlev işaretçileri için iyi, güzel temiz ve modern C++ alternatif (bu takma adı hala sonuçta işlev işaretçileri olduğunu düşünüyorum) Ama std::function iyi, güzel, temiz ve modern C++ yanı sıra dikkate almak için iyi avantajları ile. Fonksiyon işaretçilerine (veya takma adı) yapıştırmak veya std::function'u seçmek, uygulama ihtiyaçlarınıza bağlıdır.

+1

Hayır, hayır kesinlikle değil. Std :: işlevinin avantajlarını istemiyorsanız, sadece bir sözdizimi basitleştirici takma ad değil, bir şablon - gerçek bir şablon kullanın. – Puppy