// Rangarajan Krishnamoorthy, Dec 3, 2017
// Example to demoinstrate std::any (C++17 feature)

// Any.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <any>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;

void example1()
{
	any v1{ 12 };
	any v2{ "hi" };

	cout << any_cast<int>(v1) << " - " << any_cast<const char *>(v2) << endl;

	// We can assign using the appropriate cast
	any_cast<int&>(v1) = 100;

	cout << any_cast<int>(v1) << endl; // Prints 100
}

void example2()
{
	any v1; // Not initialized

	if (v1.has_value())
		cout << "variable has value\n";
	else 
		cout << "variable has no value\n";

	v1 = 12; // Assign an integer value

	if (v1.has_value())
		cout << "variable has value: " << any_cast<int>(v1) << endl;
	else
		cout << "variable has no value\n";
}

void example3()
{
	any v1{ 10 }; // Initialize with integer
	v1 = "hi"; // Assign a string

	cout << any_cast<const char *>(v1) << endl;

	v1 = 12.34; // Assign a double

	cout << any_cast<double>(v1) << endl;
}

void example4()
{
	any v1{ "hi" }; // Initialize with string
	try {
		int value = any_cast<int>(v1); // Try to get it as integer - exception thrown
	}
	catch (bad_any_cast &) {
		cout << "Bad cast from 'any' type\n";
	}
}

void example5()
{
	any v1{ 100 };

	if (v1.has_value())
		cout << "variable has value: " << any_cast<int>(v1) << endl;
	else
		cout << "variable has no value\n";

	v1.reset();

	if (v1.has_value())
		cout << "variable has value: " << any_cast<int>(v1) << endl;
	else
		cout << "variable has no value\n";
}

struct X {
	X(int v) : value{ v } {}
	int value;
};

void example6()
{
	any v1{ X{6} };
	X x{ 20 };
	v1 = x;
	cout << any_cast<X>(v1).value << endl; // Prints 20
}

struct Y {
	Y(int v) {}
	Y(const Y&) = delete; // No Copy Constructor
};

void example7()
{
	// The following won't compile because Y does not have Copy Ctor
	 any v1{ Y{0} }; 
}

void example8()
{
	any array[] = { 100, 123.45, "hello" };

	cout << sizeof(array) << endl; // Prints 120
	for_each(array, array + 3, [](auto elem) {cout << elem.type().name() << endl; });
}

struct Z {
	double array[25];
};

void example9()
{
	any v1; // Not initialized
	any v2{ 600 };
	any v3{ 1234.56 };
	any v4{ "Hello world" };
	any v5{ X(100) };
	any v6{ Z() };

	// Each of these prints 40!
	cout << sizeof(any) << " - " << sizeof(v1) << " - " << sizeof(v2) << " - " 
		<< sizeof(v3) << " - " << sizeof(v4) << " - " << sizeof(v5) << " - " 
		<< sizeof(v6) << endl;
}

int main()
{
	example1();
	example2();
	example3();
	example4();
	example5();
	example6();
	example7();
	example8();
	example9();

    return 0;
}

