#include <iostream>
using namespace std;


template <typename T>
struct St1
{
    St1 () = default;

    St1 (const St1& other) : hasValue (other.hasValue) { if (hasValue) value = other.value; }

    St1 (St1&& other) : hasValue (other.hasValue) { if (hasValue) value = std::move(other.value); }

	template <typename Arg0, typename... Args >
    explicit St1 (Arg0 arg0, Args&&... args) : hasValue (true) { value = T(std::forward<Arg0>(arg0), std::forward<Args>(args)...); }

	T value;
	bool hasValue { false };
};

template <typename T>
struct St2
{
    St2 () = default;

    St2 (const St2& other) : hasValue (other.hasValue) { if (hasValue) value = other.value; }

    St2 (St2&& other) : hasValue (other.hasValue) { if (hasValue) value = std::move(other.value); }

    explicit St2 (const T &value) : hasValue (true) { this->hasValue = value; }

    explicit St2 (T &&value) : hasValue (true) { this->value = std::move(value); }
	
	T value;
	bool hasValue { false };
};

template <typename T>
struct St3
{
    St3 () = default;

    St3 (const St3& other) : hasValue (other.hasValue) { if (hasValue) value = other.value; }

    St3 (St3&& other) : hasValue (other.hasValue) { if (hasValue) value = std::move(other.value); }

	template <typename... Args >
    explicit St3 (Args&&... args) : hasValue (true) { value = T(std::forward<Args>(args)...); }
	
	T value;
	bool hasValue { false };
};

template <typename T>
struct St4
{
    St4 () = default;

    St4 (const St4& other) : hasValue (other.hasValue) { if (hasValue) value = other.value; }

    St4 (St4&& other) : hasValue (other.hasValue) { if (hasValue) value = std::move(other.value); }

	explicit St4 (T value) : hasValue (true) { this->value = value; }

	template <typename... Args >
    explicit St4 (Args&&... args) : hasValue (true) { value = T(std::forward<Args>(args)...); }
	
	T value;
	bool hasValue { false };
};

template <typename T>
struct St5
{
	St5 () {};

    St5 (const St5& other) : hasValue (other.hasValue) { if (hasValue) value = other.value; }

    St5 (St5&& other) : hasValue (other.hasValue) { if (hasValue) value = std::move(other.value); }

	explicit St5 (T value) : hasValue (true) { this->value = value; }

	template <typename... Args >
    explicit St5 (Args&&... args) : hasValue (true) { value = T(std::forward<Args>(args)...); }
	
	T value;
	bool hasValue { false };
};


int main() {
	
	St1<int> a1;
	St1<int> a2 {2};
	St1<int> a3 {};
	
	St2<int> b1;
	St2<int> b2 {2};
	St2<int> b3 {};
		
	St3<int> c1;
	St3<int> c2 {2};
	St3<int> c3 {};
		
	St4<int> d1;
	St4<int> d2 {2};
	St4<int> d3 {};
		
	St5<int> e1;
	St5<int> e2 {2};
	St5<int> e3 {};

	cout << "St1:\n";
	cout << (a1.hasValue == 0) << '\n';
	cout << (a2.hasValue == 1) << '\n';
	cout << (a2.value == 2) << '\n';
	cout << (a3.hasValue == 0) << '\n';
	
	cout << "St2:\n";
	cout << (b1.hasValue == 0) << '\n';
	cout << (b2.hasValue == 1) << '\n';
	cout << (b2.value == 2) << '\n';
	cout << (b3.hasValue == 0) << '\n';
	
	cout << "St3:\n";
	cout << (c1.hasValue == 0) << '\n';	// failed in VS
	cout << (c2.hasValue == 1) << '\n';	// failed in VS
	cout << (c2.value == 2) << '\n';	// failed in VS
	cout << (c3.hasValue == 0) << '\n';
		
	cout << "St4:\n";
	cout << (d1.hasValue == 0) << '\n';	// failed in VS
	cout << (d2.hasValue == 1) << '\n';
	cout << (d2.value == 2) << '\n';
	cout << (d3.hasValue == 0) << '\n';
		
	cout << "St5:\n";
	cout << (e1.hasValue == 0) << '\n';
	cout << (e2.hasValue == 1) << '\n';
	cout << (e2.value == 2) << '\n';
	cout << (e3.hasValue == 0) << '\n';
	
	return 0;
}