Smart Pointers History – from 03 to 17

Smart pointerların anlatıldıgı C++03 ten C++17 standartlarına kadar nelerin değiştiğinin anlatıldıgı söyleşimize herkes davetlidir.

Smart Pointers – from 03 to 17

Friday, Mar 27, 2015, 3:00 PM

Yıldız Teknopark
İkitelli- Başakşehir Istanbul, TR

1 C++’ers Attending

Kat 1 No: 101

Check out this Meetup →

GDB Remote Debug (Windows makinesinden Linux Makinesindeki binariyi debug etme)

This is a document which I prepared at work. That why I needed to prepare it in Turkish. If people show interest I will add translation.

GDB çok faydalı bir tool. Özellikle gdbtui olarak kullanınca bizim vazgeçilmez silahlarımızdan biri oluyor . Fakat diyelimki debug etmek istediğimiz structure: “ntplInfo.u.errorData.errBuffer[0]” gibi birşey. Bu structure ‘in içine bakmak için yazıcağımız gdb komutu o kadar uzun oluyorki, gdb konsolununda pek kullanıcı dostu olmamasından dolayı çalışmak imkansız hale geliyor . Bunun için user interface desteği almamız gerekiyor. Ben aşağıda eclipse araçılığıyla linux binarisini nasıl debug ederiz anlatmaya çalışacağım.

Şimdi adımları tarifi vermeden önce kullanıcağımız malzemelerden bahsedelim .

1- Linux makinesinde gdb ve gdbserver , versiyonlar 7.6 veya üstü olmalıdır.

2 – Windows makinesinde gdb’nin aynı versiyonun kurmalıyız. Bunun için mingw indirmemiz lazım. Yanı sıra derleyebilmemiz için expat isimli projeyi de manuel derlememiz lazım . Bunlardan sonra gdb yi derleyebiliriz .

3 – Eclipse ve eclipse pluginleri . Eclipse ‘in remote connection ile ilglli bütün core pluginlerine sahip olmamız lazım . Pluginler default geliyor zaten çok merak etmeyin .

Şimdi Gelelim Tarife:

1 – Zaten sistem takımımz tarafından GDB ve gdb server linux makinelerine kuruluyor . Siz yinede kontrol edin .

2- GDB yi linuxde default çalıştırın , x86_64-unknown-linux-gnu gibi bir banner görüceksiniz. Bunu note edin ileride kullanıcağız.

3- Mingw ‘yi indirin cvgwin ile denemeyin sorun çıkıyor .

4 -Expat source kodunu inidirin. Ve mingwden indirdiğin folder’A gidip ./configure , make , make install yapın.

5- GDB 7.7 nin source kodunu indirin  .”./gdb-7.4/configure –with-expat –target=x86_64-unknown-linux-gnu –host=i686-pc-mingw32″ ile konfigure edin .Ve sonra make ve make install yapın.

Şimdi gelelim ,manuel testte acaba bu adıma kadar herşeyi yaptıkmı . Ben burada yaklaşık 3-4 saat kaybettim umarım siz bu yazının sayesinde kaybetmezsiniz.

6 – Linux makinesinde dummy bir proje oluşturalım ismide hello olsun . Hello ‘u g++47 -g -o hello hello.cpp diyerek derleyelim.

7 – Linux makinesinde gdbserver ‘ı çalıştıralım : “gdbserver –debug localhost:10000 hello”, ben 10000 portunu seçtim sizin keyfiniz bilir

8 – 10000 portunu açalım yoksa OS reject ediyor (3-4 saat burda kaybettim)

[root@tux ~]# iptables -I INPUT -p tcp –dport 10000 –syn -j ACCEPT
[root@tux ~]# iptables -I INPUT -p tcp –sport 10000 –syn -j ACCEPT

9 – Windows makinesine hello binarisini ve hello.cpp’yi kopyalıyalım.

10 – Mingw ‘den hello ‘nun bulunduğu dizine gidip “./gdb  hello” ile çalıştıralım. Ve sonrada “target remote 172.16.42.244:10000” komutu ile linux makinemizdeki(172.16.42.244) gdbserver ‘a bağlanalım.

image2014-6-4 14-6-56  console’dan testlerimizi yaptık. Ama asıl amaçımız eclipseden bir GUI yardımı ile bunu başarmak.

11  –  Eclipse ‘e geçmeden önce son olaraki global variable ‘lara mingw/bin path ini ekleyelim(sizin mingw niz nerdeyse ona göre ayarlayın). Ve yukardaki adımları windows cmd ‘den deneyin global variable ‘ı doğru set ettiyseniz herşey yukardaki gibi çalışacaktır .

Geldik eclipse kısmına, eclipse bir sürü butonlar ve opsiyonlar koymuş fakat bir çoğu bizim konumuzla alakasız ve kafa karıştırıcı.

12 – Eclipse ‘de projenizi seçin, benim bu örnekte anlataçağım artık hello değil napa_project olacak. run–>debug_configurations penceresini açın. Burda sol menüde “C/C++ attach to application”  opsiyonun seçin diğerleri benim gibi zaman kaybetmenize neden olacaktır.

13 – C/C++ application kısmına debug etmek istediğiniz binariyi şeçin, project olarak debug etmek istediğiniz projeyi şeçin. Benim için ekran çıktısı:

image2014-6-4 20-18-52

14 – Aynı tabde şimdi debugger ‘a gelin, debugger olarak gdbserver şeçin , gdb olarak windows ‘a yeni kurduğumuz gdb binarisini seçin . GDB command file ‘I .gdbinit olarak bırakın .

image2014-6-4 20-21-52

15 – GDBSERVER seçtiğinizde debugger tab’ında  yukarda gözüktüğü gibi Connection sekmesi açılacaktır . host ip yi(linux ip si) ve gdbserver ‘in dinlediği portu(10000) buraya yazın .

image2014-6-4 20-23-11
16 – .gdbinit dosyasının içine aşağıdaki satırları kendinize uygun olarak girin

file test
b main
set solib-absolute-prefix /root/erdemdem/napa_project/
set solib-search-path /lib64

17 – Eğer warning: Could not load shared library symbols for 11 libraries, e.g. /opt/napatech3/lib/libntapi.so.

gibi bir warning alıyorsanız

set solib-search-path /opt/napatech3/lib/ , gibi gdbinit dosyasına eklendi yapın buraya bir kere koymanız gerekecek her gdb çalıştığında her zaman otomatik çalışacaktır.

18 – Linux tarafında gdbserver ayakta ve listening modda olduğunda emin olun ,

19 – Debugı başlatın , gdbinit ‘e b main koyduğumuzdan main ‘de duracaktır .

20 – GUI den break point, next ,continue gibi testleri yapın

Sonuç : unlimited debugging powerrrr

image2014-6-4 20-29-40

SharpEar Multi Channel Acoustic Camera Simulation

SharpEar is a open source “Microphone array” simulation project.
SharpEar simulates a “Microphone Array” and “Room”.
User can add voice, noice, moving voices in to the Room. After User selects a .wav file and a position for this sound in the room; user can trigger beamforming . According to the position of the “Microphone Array” and “Sound Sources” beamforming will color the room. User can choose a “Sound” as “Noice”, “Voice” or even a Moving “Voice”.

Features

  • Room Simulation For Microphone Array
  • Wav files will be read and could be attached any point in the room
  • Sounds could be categorized by User as noice,sound or moving sound.
  • Beamforming and Room Coloring according to beamforming result in each point
  • Speaker Identification
  • Adaptive Beamforming according to speaker identification

Links :

https://sourceforge.net/projects/sharpear/

https://github.com/kerdemdemir/sharpEar

sharpEarOutput

Macro’s vs Variadic Templates – 2

Former article was visited by C++ fans from around the world. Therefore i decided to publish my article in english. Thanks for visiting web site.

More Generic Design
You know templates provide more generic design than function overloading. And now with C++11, you can even design more generic templates than templates, so variadic templates.

I want to write a function that gives me size of all containers in STL(even if they almost all have a size function 🙂 ). You know STL has two main container types:
– Sequence Containers
– Associative Containers

Sequence containers take 2 arguments ValueType and mainly Allocator:

template<class T,
         class Allocator = std::allocator<T>
         > class SeqContainer;

I will try to implement my function-template for sequence containers.

template < template <typename, typename> class ContainerType, typename ValueType, typename Alloc>
size_t sizeOfContainers(ContainerType<ValueType, Alloc> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

As you see first template parameter “template class ContainerType” is a template class as template parameter. Second and third one are template parameters of first parameter.

But that function template will not work for std::array type. We will look that problem later. Mainly this function satisfies our needs.

#include <vector>
#include <iostream>
#include <memory>
#include <map>
#include <forward_list>
#include <unordered_set>
#include <array>

using namespace std;

template < template <typename, typename> class ContainerType, typename ValueType, typename Alloc>
size_t sizeOfContainers(ContainerType<ValueType, Alloc> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}



int main()
{
    vector<int> v({1, 4, 5, 3, 5, 6});
    forward_list<int> fl ({ 34, 99, 10, 71});
    
    cout << sizeOfContainers(v) << endl;
    cout << sizeOfContainers(fl) << endl;

   
  return 0;
}

Associative containers take 3 or 4 arguments for example:

std::set

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> class set;

std::map

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class map;

std::unordered_set

 
template<
    class Key,
    class Hash = std::hash<Key>,
    class KeyEqual = std::equal_to<Key>,
    class Allocator = std::allocator<Key>
> class unordered_set;

Therefore we need two more overload for our function to handle this containers. Let’s try to write them :


template < template <typename, typename, typename> class ContainerType, typename FirstType, typename SecondType, typename AllocType>
size_t sizeOfContainers(ContainerType<FirstType, SecondType,  AllocType> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

template < template <typename, typename, typename, typename> class ContainerType, typename FirstType, typename SecondType, typename ThirdType, typename AllocType>
size_t sizeOfContainers(ContainerType<FirstType, SecondType, ThirdType, AllocType> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

As you see for that functions can handle this issue for different type.

But now we have three overloads, can we reduce it to one function with variadic functions ? Lets try it:

template <template <typename, typename...> class ContainerType, typename FirstType, typename... Types> 
size_t sizeOfContainers(ContainerType<FirstType, Types...> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

Now we can handle all 2,3,4 parameter containers. Except one std::array. std::array takes two parameter:

template< 
    class T, 
    std::size_t N 
> struct array;

Remember, we discussed variadic template function creation at first article. In that example our variadic function will not create function that we need for std::array. Actually second type of std::array is not a type, it is a constant. And it is not allowed in C++, also compile time error. Function overloading take responsibility for us :

template <template <typename, size_t> class ContainerType, typename FirstType, size_t S> 
size_t sizeOfContainers(ContainerType<FirstType, S> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

That overload will handle our issue. Sometimes we need partial specialization overloads to resolve problems.

At the end of the day score is on the board:

Variadic templates 3 – 1 Function overloading

Full Source Code:

#include <vector>
#include <cstdlib>
#include <iostream>
#include <memory>
#include <map>
#include <forward_list>
#include <unordered_set>
#include <array>
#include <set>
#include <deque>

using namespace std;


template <template <typename, typename...> class ContainerType, typename FirstType, typename... Types> 
size_t sizeOfContainers(ContainerType<FirstType, Types...> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}


template <template <typename, size_t> class ContainerType, typename FirstType, size_t S> 
size_t sizeOfContainers(ContainerType<FirstType, S> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

template < template <typename, typename> class ContainerType, typename ValueType, typename Alloc>
size_t sizeOfContainers(ContainerType<ValueType, Alloc> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

template < template <typename, typename, typename> class ContainerType, typename FirstType, typename SecondType, typename Alloc>
size_t sizeOfContainers(ContainerType<FirstType, SecondType,  Alloc> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}

template < template <typename, typename, typename, typename> class ContainerType, typename FirstType, typename SecondType, typename ThirdType, typename Alloc>
size_t sizeOfContainers(ContainerType<FirstType, SecondType, ThirdType, Alloc> &c)
{
    size_t s = 0;
    for (auto element : c) {
        s++;
    }
    return s;
}



int main()
{
    vector<int> v({1,2,3,4,5,6});
    map<int, int> m({ {2,3},  {4, 5}});
    set<int> s({8, 7});
    deque<int> d = {10,20,30};
    forward_list<int> fl ({ 34, 77, 16, 2 });
    array<int,10> a = { 2, 16, 77, 34, 50};
    unordered_set<string> us = {"C++", "UG","ISTANBUL","69736c616d"};
    

    cout << sizeOfContainers(v) << endl;
    cout << sizeOfContainers(m) << endl;
    cout << sizeOfContainers(fl) << endl;
    cout << sizeOfContainers(us) << endl;
    cout << sizeOfContainers(s) << endl;
    cout << sizeOfContainers(a) << endl;
    cout << sizeOfContainers(d) << endl;
    
  return 0;
}

Debugging with GDB – C++ UG Meetup

28 Kasım Cuma günü saat 15:00’de “Debugging with GDB” adlı seminerimize herkes davetlidir.

Debugging with GDB

Friday, Nov 28, 2014, 3:00 PM

Teknopark Istanbul Konferans Salonu
Teknopark Istanbul Pendik Istanbul, TR

3 C++’ers Attending

Check out this Meetup →

Macro’s vs Variadic Templates – 1

Variadic fonksiyonlar istenilen sayıda değişken almaları sayesinde bir çok işi kolaylaştırmışlardır. C++11 den önce C de bu ihtiyaç “…” elipsis operatörü ve va_* makrolarıyla çözülüyordu. Fakat bu çözüm çalışma zamanında işlediğinden yanlış kullanım veya beklenmedik durumlarda çalışma zamanı hataları veya seg fault dahi alınabiliyordu.

Örneğin;

int a ;

printf("%s", a);

Bu kod örneği derleme zamanında (compile time) hata vermez. Fakat çalışma zamanında seg fault alırsınız. C++11 de bu problem variadic templatelerle çözülüyor. Üstelik derleme zamanında çözüldüğü için yanlış kullanım durumunda hemen müdahale edebiliyorsunuz.

Variadic templates

Basit bir önekle devam edelim;

#include <iostream>

using namespace std;

template<typename T>
void println(T v) //A
{
    cout << v << endl;
}

template<typename T, typename... Types>
void println(T first, Types... values) //B
{
    println(first);
    println(values...);
}

int main()
{
   println("islam", "cppistanbul", 1299); //1
   println(6, 1, 0, "c++UG", 5, 7, 1); //2
  
  return 0;
}

“typename… Types” şablon parametre paketi(template parameter pack), “Types… values” ise fonksiyon parametre paketi (function parameter pack) şeklinde adlandırılıyor. template parameter packteki Types aslında bir tür listesi. Örneğin “1” durumunda bu liste “const char *, const char *, integer” şeklindedir.Function parameter pack ise bir değer listesidir. Yine “1” durumunda bu liste “islam, cppistanbul, 1299” şeklindedir. Elipsis (…) operatörüyle de bu değerler ve türler açılır(expand). Burda dikkat ederseniz iki tane println fonksiyonu var, basitçe bir oveload aslında. Bu overload ile aslında kısmi bir rekürsiv çağrı yapıyoruz. Daha iyi anlaşılması için adım adım ilerleyelim.

1.iterasyon:

“1” durumunda println fonksiyonu 3 tür ie çağırılmış. Template argument deduction yaparak B deki overload çağrılacak ve:

void println(T, Types ...) [with T = const char*; Types = {const char*, int}]

parametre bu şekilde belirlenecek. Derleyici bir tane yukarıdaki imzaya sahip bir fonksiyon oluşturacak. Ve dikkat edin A durumundaki tek parametreli template de şu şekilde derleyici tarafından yazılacak:

void println(T) [with T = const char*]

2. iterasyon:

B template fonksiyonu:

void println(T, Types ...) [with T = const char*; Types = {int}] 

şeklinde, A template fonksiyonu ise yine aynı imzaya sahip olacağından tekrar yazılmayacak.

3. iterasyon

Bu durumda ise sadece tek tür kaldıgından direkt olarak A template fonksiyonu tercih edilecek(argument deduction). Ve aşağıdaki imzaya sahip bir fonksiyon derleyici tarafından yazılacak:

void println(T) [with T = int]

Bu sayede println fonksiyonuna verdiğimiz değerlere uygun overload edilmiş println fonksiyonu çağıralarak ekrana bu değerler yazılmış olacak.

To be continued :))

C++11 R-value References and Move Semantics

17 Ekim Cuma Günü C++11 Sağ değer referansları ve Move semantiği hakkında Teknopark İstanbul teknoloji geliştirme ofisinde saat 15:00-17:00 arasında seminerimiz vardır. Etkinlik herkese açık ve ücretsizdir.

Edit: Daha önce 2 Ekim olarak duyurduğumuz etkinlik tarihi 17 ekime alınmıştır.

Lambda İFADELERİ – C++11

C++11’le gelen bence en iyi özelliklerden biri de lambda ifadeleridir. Aslında yavaş yavaş nesne yönelimli programlamanın yerine fonksiyonel programlamanın (Functional Programming) alacağı öngörülüyordu. Lambda fonksiyonlar, auto anahtar kelimesiyle beraber FP ve multi-threading-concurrency’ye de ciddi manada destek verilmiş oldu. Zaten inşallah başka bir makalenin konusu olarak C++11 le gelen Thread(Boost.Thread) kütüphanesini inceleyeğiz. Şimdi lambdalara devam edelim.

Lambda fonksiyonlar aslında fonksiyon göstericileriyle (function pointers) başlayan Functorlarla devam eden gelişimin son halkası.

Sentaks:


#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{    
    auto p = [] () -> string { return "Hello World";};
    
    cout << p() << endl;
   
    return 0;
}

[] : Lambda fonksiyonlar bu ifadeyle başlar. Aslında adı “capture specification”‘dır. Birkaç satır sonra neden bu adın verildiğini daha detaylı anlamış olacağız. Kısacası derleyici bu ifadeyi gördüğünde bir lambda ifadesinin başladığını anlar.
() : Bu ifade olağan fonksiyonlarda olduğu gibi parametre listesini verdiğimiz fonksiyon çağrı operatörü.
-> return value : Bu ifade ise lambda fonksiyonun geri dönüş değerini belirtir. Fakat bu ifade vermesekte derleyici geri dönüş değerini otomatik olarak tespit edecektir. Üstteki örnekte “-> string” ifadesini silsek dahi kod çalşacaktır.

Değişken Aktarımı
Lambda fonksiyonlarını bir diğer özelliği ise bulunduğu isim alanından değişkenleri kendi gövdesine enjekte edebilme yeteneğidir. Bunu hem by value hem de by reference şeklinde yapabilir. Örneğin:

[&] () {} : Bu ifade de isim alanı içerisindeki nesnelerin tümünü “by reference” olarak enjekte ederiz. Eğer örneğin [&a] () {} şeklinde yazarsak sadece ilgili değişkeni enjekte edebiliriz.

#include <iostream>

using namespace std;

int main()
{
	
	int a = 5;
	
	cout << a << endl;
	
	auto p = [&a]() { a = 6;};
	
	p();
	cout << a << endl;
}

[=] () {} : “=” ifadesi ile isim alanı içerisindeki nesneleri “by value olarak” elde ederiz. Yine aynı şekilde [=, &a] () {} şeklinde bir bildirim yaparsak a by referans olarak geri kalan değişkenler değer olarak lambda fonksiyonuna iletilir.

Lambda ve STL:
STL’de kütüphanesinde bulunan fonksiyonlarda kullanımı oldukça pratiktir. Örneğin:

#include <iostream>
#include <algorithm>

using namespace std;




int main()
{	
	vector<string> vs;
	vs.push_back("islam");
	vs.push_back("cpp");
	vs.push_back("turkiye");
	
	
	for_each(vs.begin(), vs.end(), [] (string s) { if (s == "islam") cout << s << endl;});
	
	auto p = remove_if(vs.begin(), vs.end(), [] (string s) { if (s == "cpp") return true; return false; });

	for (auto s = vs.begin(); s != p; s++)
		cout << *s << endl;
}

Peki bir lambda ifadesini başka bir fonksiyona veya sınıfa parametre olarak vermek istediğimizde nasıl bir yol izleyeceğiz. Burda imdada std::function şablon sınıfı yetişiyor. Örneğin:

#include <iostream>
#include <algorithm>

using namespace std;

class A {
private:
	string s;
	function<void (string)> handler_func;
public:
	A(function<void (string)> f) : handler_func(f), s("cppturkey.org"){}
	
	void operator ()() { handler_func(s);}
};

int main()
{	auto f = [](string s) { cout << s << endl;};
	A a(f);
	a();
}

“function<void (string)> ” ifadesi geri dönüş değeri void olan ve parametre olarakta string alan bir fonksiyon objesini belirtmektedir.

Gelecekte lambda fonksiyonlarının concurrency ve Functional Programming ile beraber daha sık kullanıldığına şahit olacağız.

C++11 SAĞ DEĞER REFERANSLARI (R-VALUE REFERENCES) – 2

Bir önceki bölümde vector<string> dizisinin eski yöntemlerle kopyalanmaya kalktığında nasıl bir maliyet oluşturacağına dikkat çekmiştik. Şimdi bu örnek üzerinden gidelim.

Eski tarz vector kopyalanması:


#include <iostream>
#include <typeinfo>
#include <vector>

using namespace std;


void copyVector(vector<string> &v1, vector<string> &v2)
{
    for (auto s : v1) {
        v2.push_back(s);
    }
}


int main(int argc, char** argv) 
{
    vector<string> v1;
    vector<string> v2;

    v1.push_back("islam");
    v1.push_back("cpp");
    v1.push_back("turkiye");
    
    
    copyVector(v1, v2);
    
    for (auto s : v2)
        cout << s << endl;
   
    return 0;
}

Burda dikkat ederseniz v2 vektörüne 3 string nesnesi oluşturularak ekleniyor. Yani string sınıfının ctorları vasıtasıyla bu değerlerle v2 sınıfında bu nesneler inşaa ediliyor. Aynı şekilde
v2.push_back(s);
yerine
v2.push_back(std::move(s)) kullanırsak copy yerine move edecek. Bu arada derleyicinizin zaten c++11 uyumlu ise otomatik olarak move edecektir. __GXX_EXPERIMENTAL_CXX0X__ değişkenini tanımladığı için kopyalama maliyetinden kurtulmuş olacaksınız.

Peki std::move() kullanılarak move edilen nesneleri nasıl yakalayacağız. Bunun içinde move ctor şöyleki:

class cVector
{

public:
	cVector(cVector &&r)
	{
		cout << "rvalue move ctor" << endl;
	}
	
	cVector& operator= (cVector &&r)
	{
		cout << "operator = rvalue" << endl;
		return *this;
	}
	
	cVector & operator= (cVector&r)
	{
		cout << "operator = lvalue" << endl;
		return *this;
	}
	
	cVector ()
	{
		cout << "Default ctor" << endl;

	}
};

int main()
{
	cVector cv;
	cVector cv2(move(cv));

	cv = cv2;
	cv = move(cv2);
}

2-Perfect Forwarding

Bu durum rvalue referansları fonksiyon şablonlarında kullanmak isteyince “template argument deduction” yani fonksiyon argümanı belirleme durumunda ortaya çıkıyor. Şöyle ki:

template<typename T>
void f(T&& t);

int main()
{
    X x;
    f(x);   // 1
    f(X()); // 2
}

Örnekte 1 durumunda f fonksiyonuna bir lvalue parametre olarak verilmiş dolayısıyla T türü X& olarak belirlenecektir. 2 durumunda ise f fonksiyonuna bir rvalue reference geçilmiş böylelikle T türü X olarak belirlenecektir. Peki f fonksiyonu içerisinde başka bir fonksiyon çağırılmak istense nasıl gelen nesnenin rvalue mu lvalue mu oldgunu bileceğiz ?

void g(X&& t); // A
void g(X& t);      // B

template<typename T>
void f(T&& t)
{
    g(std::forward<T>(t));
}

void h(X&& t)
{
    g(t);
}

int main()
{
    X x;
    f(x);   // 1
    f(X()); // 2
    h(x);   // 3
    h(X()); // 4
}

Örnekte std::forward(t) yardımıyla gelen tür bir rvalue ise; içerisinde static_cast(t) operatörünü görüldüğü gibi çağırarak A durumundaki g fonksiyonun çağırılmasını sağlar. Gelen nesne bir lvalue ise B durumundaki g fonksiyonu çağırılacaktır(std::forward gelen nesne bir lvalue ise sadece aldığı argümanı geri döndürür). İşte tam olarak gelen argümanın tespitine göre içeride uygun fonksiyonun çağırılmasına perfect forwarding denir.

Normal fonksiyonda (h) ise (3,4) durumunda uygun overload çağırılır. Fakat A satırındaki g nin rvalue overload fonksiyonu silinse dahi çalışır. Çünkü gelen nesne bir rvalue referansa bir lvalue referanstır. g fonksiyonunun içinde yapılanlara göre tehlikeli bir durum olabilir.