//Rafał Wilk I1ISI

//Plik przedstawia zastosowanie generycznej klasy boost::value_initailized<T>,
//która zapewnia inicjację obiektu domyślną wartością w momencie deklaracji.

#include <boost/utility/value_init.hpp>
#include <boost/utility.hpp>
#include <iostream>
#include <string>

using namespace std;
using namespace boost;

//Klasa pomagająca zobrazować zastosowanie klasy boost:value_initialized<T>
class Data
{
protected:
	int value;
	char character;
public:
	int getValue() {return value;}
	char getChar() {return character;}
};

void print(int& i)
{
	//dowolny kod
};

int main()
{
	//--- Wstęp --//

	//By zainicjować zdeklarowanego int'a wartością zero należy użyć jednego z poniższych sposobów:
	int a = 0;
	int b = int();
	int c = initialized_value;
	//lub też zdeklarować go kożystając z klasy value_initialized
	value_initialized<int> x;

	
	//--- Podstawowe zastosowania ---//

	//Prosty przykład pokazujący podstawowe zastosowanie value_initialized:
	
	int x_std;
	value_initialized<int> x_v_init;
	
	//W zależności od systemu deklaracja int x_std; utworzy int'a zainicjowanego 
	//niezdeterminowaną wartością(Windows) lub zerem. Używając value_initialized pewnym jest, 
	//iż int ma wartość 0(jest to domyślna wartość inicjacji int'a).

	cout<< "\"int x;\":"<< endl << "\tx = " << x_std 
		<< endl << endl<< "\"value_initialized<int> x;\":"<< endl << "\tx = " << x_v_init << endl << endl;
	
	
	//Następny przykład dotyczy inicjacji wskaźników:
	
	value_initialized<Data*> ptr;

	if(ptr != NULL)
		delete ptr;
	
	//w momencie gdy ptr nie został zainicjowany zerem, jak mogło się wydarzyć gdyby deklaracja
	//wyglądała następująco Data* ptr; zaistniała by próba usunięcia obiektu Data spod losowego
	//adresu.

	
	//Te same zasady dotyczą innnych typów zmiennych, klas, wskaźników.
	//Warunkiem skorzystania z value_initialized jest by posiadanie domyślnego konstruktora
	
	Data d_std;
	
	value_initialized<Data> d_v_init;
	
	//składowe klasy Data zostały zainicjowane zerem.

	cout<<"\"Data d;\"" << endl << "\td.value: "<< d_std.getValue() << endl 
		<< "\td.character: '" << d_std.getChar() << "'" << endl << endl;

	cout<<"\"value_initialized<Data> d;\"" << endl << "\td.value: "<< get(d_v_init).getValue() 
		<< endl << "\td.character: '" << get(d_v_init).getChar() << "'" << endl << endl;

	
	//Kolejnym przykładem jest inicjacja domyślna klas dziedziczących po boost::noncopyable lub nieposiadających
	//lub posiadających prywatny konstruktor kopiujący wtedy konstrukcja inicjująca wartością domyślną:
	
	Data d = Data();
	
	//nie ma prawa zadziałać natomiast value_initialized spełni swoją rolę, zastępując powyższy kod.

	
	//Deklarując typ bool inicjowany jest on domyślnie wartością false,co doskonale nadaje się do tworzenia 
	//zmiennych kontrolujących wystąpienie błędu, zapełnienia, zajętości. 
	value_initialized<bool> is_busy;
	if(is_busy)
		;//stop
	else
		;//pracuj
		
	
	//--- Dostęp do referencji do wartośći deklarowanego typu --//
		
	//Istnieją trzy możliwości uzyskania referencji do zadeklarowanego typu:
	
	//1. operator T& ()
	print( x_v_init );
	
	//2. metoda T& data()
	print( x_v_init.data() );
	
	//3. funkcja T& get( value_initialized<T>& x ) która posiada też wersję T const& get ( value_initialized<T> const& x )
	print( get(x_v_init) );

	
	//--- value_initialized<T> a wartości const ---//

	//Metoda data() klasy value_initialized zwraca zawsze referencję "nie const" bezwzględu na to czy obiekt jest const,
	//może to prowadzić do modyfikacji obiektu chronionego przed zmianą. Dlatego też zaleca się stosowanie funckji get(),
	//zapewnia ona poprawne kontrolę niezmienności.

	value_initialized<int> integer ;
	get(integer) = 1; //poprawny kod

	value_initialized<int const> const_integer ;
	//get(const_integer) = 1;  //błąd nie można zmodyfikować obiektu const

	value_initialized<int> const integer_const ;
	//get(integer_const) = 1;  //błąd nie można zmodyfikować obiektu const

	value_initialized<int const> const const_integer_const ;
	//get(const_integer_const) = 1;  //błąd nie można zmodyfikować obiektu const
}

