Thread overview
std::forward
Apr 10, 2018
hsencan
Apr 11, 2018
kerdemdemir
Apr 11, 2018
hsencan
Apr 11, 2018
kerdemdemir
Apr 11, 2018
hsencan
April 11, 2018

Herkese Merhaba,

C++ ta araştırdığıma göre templateler ile birlkte kullanılan std::forward ne işe yarıyor ? Baktıklarımdan pek anlayamadım.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2018

std::forward uzerine gelen elemanlari oldugu gibi aktariyor. Benim bildigim en bilindik kullanimi std::vector::emplace_back, std::make_shared, std::make_unique .

Ornegin std::vector'u ele alalim . Eskiden std::forward'i kullanan emplace_back() gibi bir fonksiyonumuz yoktu.
Hep push_back kullanmak zorunda kaliyorduk.

Ornek olarak:

struct Yapi
{
   Yapi( YapiTasi )
  {
  }
}

struct YapiTasi
{
}

YapiTasi yapiTasi;
std::vector<Yapi> yapi;

yapi.push_back(Yapi(yapiTasi)); // Bu ornekde extra bir Yapi olusturmak sorundayim.
//Benim gereksiz gecici objem sonra vectore kopyalanacak.
//Eger derleyici optimize etmezse bu gecici obje gereksiz yere yaratilmis oluyor.
//std::forward gibi araclar olmazsa C++ cok fazla kopyalama gerektiren bir dil.

yapi.emplace_back(yapiTasi); // emplace_back'de ise std::forward kullanilarak parametreler
// Yapi objesinin constructor"ina aktariliyor.
//Ve yapi gereksiz ara kopyalama olmadan direk olusturuyor.

Umarim benim ornegim aciklayici olmustur. Bu guzel performans kazanci disinda ayrica daha az sey yaziyoruz bu std::forward ile yapilmis seyler sayesinde buda onemli bence.

Erdemdem.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2018

Teşekkürler, gayet açıklayıcı olmuş.
Peki direk constructor"ina aktatılıyor dediniz. Başka parametre olsa onu da std::forward ile gönderebiliyoruz değilmi ? Umarım doğru anlamışımdır.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2018

Benim verdiğim örnekte constructor'ı aktarılıyor ve ben örneğimde bir tane parametre kullanıyordum.

Benim yaptığımı iki parametre ile de yapabilirdik. Umarım sorun buydu.

https://onlinegdb.com/HJYH8AssG

Ama sorun eğer constructor hariç bir kullanımı varmıdır ise ne yazıkki ben başka bir iş için kullanmadım. İnternetten araştırdım sen sorunca "reference unfolding" denen olay için kullanılıyormuş ama benim işim düşmedi şimdilik.

Kullanmadığım kısımlarından yorum yapmaktan çekindiğimden topu Ali Abi'ye atıyorum bu noktada.

Erdemdem

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 11, 2018

Alıntı:

>

Benim yaptığımı iki parametre ile de yapabilirdik. Umarım sorun buydu.

Evet sorum buydu. Yardımınız için teşekkürler.

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

April 13, 2018

"Rvalue reference" kavramı C++'a eklenmeden önce "perfect forwarding" konusunda bir sorun vardı. (Ben de bu sorunla C++11'den önce karşılaşmıştım.)

Aşağıdaki programda 'hata_at' diye genel bir işlev tanımlamak istiyoruz. Hata atmadan önce bazı ön işlemler yapacağız ve ondan sonra verilen parametre değerlerini kullanarak belirtilen türde bir hata atacağız.

C++98'in ilk sorunu, parametre adedine göre bu işlevlerden gerektiği adette tanımlamaktı. Aşağıdaki kod yalnızca iki parametreli yükleme kullanıyor; genel bir kütüphanede 10 veya daha fazla adede kadar tekrarlamak gerekirdi. (C'de bazı makrolarda da yaşanan durum.)

#include <exception>
#include <iostream>
#include <string>

using namespace std;

class Hata : public exception {
   int bilgi;
   string baska_bilgi;

public:

   Hata(int _bilgi, string _baska_bilgi)
       :
       bilgi(_bilgi),
       baska_bilgi(_baska_bilgi)
   {}

   // ...
};

// Normalde bu islevden farkli parametre adetlerine karsilik N adet yazilir
template <class T, class Arg0, class Arg1>
void hata_at(Arg0 arg0, Arg1 arg1) {
   cout << "Hata atiyorum";
   throw T(arg0, arg1);
}

int main() {
   hata_at<Hata>(42, "merhaba");
}

Asıl sorun, şablonun parametrelerinin değer olarak mı yoksa referans olarak mı geçirileceğinin belirlenememesidir. Ben 'Arg0' diye değer olarak yazdım ama bazı durumlarda 'Arg0&' olması daha etkindir veya şarttır (örneğin, gerçekten de bir nesnenin referansı geçirilmek isteniyordur.)

C++11'in variadic template parameter olanağı bu sorunların hepsini çözer: http://en.cppreference.com/w/cpp/language/parameter_pack

forward, parametreleri sol değer (lvalue) ve sağ değer (rvalue) olmalarını da göz önüne alarak gerektiğinde değer olarak, gerektiğinde referans olarak iletir. Yukarıdaki program C++11'den sonra şöyle yazılabilir. (Derlenmiyor çünkü doğru söz dizimini beceremedim. Ha ha ha! :) ):

#include <exception>
#include <iostream>
#include <string>
#include <utility>

using namespace std;

class Hata : public exception {
   int bilgi;
   string baska_bilgi;

public:

   Hata(int _bilgi, string _baska_bilgi)
       :
       bilgi(_bilgi),
       baska_bilgi(_baska_bilgi)
   {}

   // ...
};

template <class T, class ... Args>
void hata_at(Args ... args) {
   cout << "Hata atiyorum";
   throw T(forward(&args...));
}

int main() {
   hata_at<Hata>(42, "merhaba");
}

Orada forward'a gerek olup olmadığından bile emin değilim. :/

C++'ın karmaşıklığı akıl alır gibi değil. :/ Ek olarak, bu olanak D (ve başka dillerin) programcıları tarafından senelerce büyük rahatlıkla kullanıldığı halde bazı C++'çılar C++'ın icadı sanırlar. Yine, bazı C++'çılar başka dillerden haberleri olmadıklarından bu karmaşıklıkların gerekli olduklarını düşünüp bu nimetten mutlulukla yararlanırlar.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]