EDIT1: Improved with throw exception on "null" Value. More fixes
EDIT2: An alternative version supporting nullable references can be found here.
If Boost.Optional or std::optional are not an option, in c++11 you can also take advantage of nullptr and the nullptr_t typedef to create a Nullable<T> with pretty much same semantics as .NET one.
#pragma once
#include <cstddef>
#include <stdexcept>
template <typename T>
class Nullable final
{
public:
    Nullable();
    Nullable(const T &value);
    Nullable(std::nullptr_t nullpointer);
    const Nullable<T> & operator=(const Nullable<T> &value);
    const Nullable<T> & operator=(const T &value);
    const Nullable<T> & operator=(std::nullptr_t nullpointer);
    bool HasValue() const;
    const T & GetValueOrDefault() const;
    const T & GetValueOrDefault(const T &def) const;
    bool TryGetValue(T &value) const;
    T * operator->();
    const T * operator->() const;
    T & operator*();
    const T & operator*() const;
public:
    class NullableValue final
    {
    public:
        friend class Nullable;
    private:
        NullableValue();
        NullableValue(const T &value);
    public:
        NullableValue & operator=(const NullableValue &) = delete;
        operator const T &() const;
        const T & operator*() const;
        const T * operator&() const;
        // https://stackoverflow.com/questions/42183631/inability-to-overload-dot-operator-in-c
        const T * operator->() const;
    public:
        template <typename T2>
        friend bool operator==(const Nullable<T2> &op1, const Nullable<T2> &op2);
        template <typename T2>
        friend bool operator==(const Nullable<T2> &op, const T2 &value);
        template <typename T2>
        friend bool operator==(const T2 &value, const Nullable<T2> &op);
        template <typename T2>
        friend bool operator==(const Nullable<T2> &op, std::nullptr_t nullpointer);
        template <typename T2>
        friend bool operator!=(const Nullable<T2> &op1, const Nullable<T2> &op2);
        template <typename T2>
        friend bool operator!=(const Nullable<T2> &op, const T2 &value);
        template <typename T2>
        friend bool operator!=(const T2 &value, const Nullable<T2> &op);
        template <typename T2>
        friend bool operator==(std::nullptr_t nullpointer, const Nullable<T2> &op);
        template <typename T2>
        friend bool operator!=(const Nullable<T2> &op, std::nullptr_t nullpointer);
        template <typename T2>
        friend bool operator!=(std::nullptr_t nullpointer, const Nullable<T2> &op);
    private:
        void checkHasValue() const;
    private:
        bool m_hasValue;
        T m_value;
    };
public:
    NullableValue Value;
};
template <typename T>
Nullable<T>::NullableValue::NullableValue()
    : m_hasValue(false), m_value(T()) { }
template <typename T>
Nullable<T>::NullableValue::NullableValue(const T &value)
    : m_hasValue(true), m_value(value) { }
template <typename T>
Nullable<T>::NullableValue::operator const T &() const
{
    checkHasValue();
    return m_value;
}
template <typename T>
const T & Nullable<T>::NullableValue::operator*() const
{
    checkHasValue();
    return m_value;
}
template <typename T>
const T * Nullable<T>::NullableValue::operator&() const
{
    checkHasValue();
    return &m_value;
}
template <typename T>
const T * Nullable<T>::NullableValue::operator->() const
{
    checkHasValue();
    return &m_value;
}
template <typename T>
void Nullable<T>::NullableValue::checkHasValue() const
{
    if (!m_hasValue)
        throw std::runtime_error("Nullable object must have a value");
}
template <typename T>
bool Nullable<T>::HasValue() const { return Value.m_hasValue; }
template <typename T>
const T & Nullable<T>::GetValueOrDefault() const
{
    return Value.m_value;
}
template <typename T>
const T & Nullable<T>::GetValueOrDefault(const T &def) const
{
    if (Value.m_hasValue)
        return Value.m_value;
    else
        return def;
}
template <typename T>
bool Nullable<T>::TryGetValue(T &value) const
{
    value = Value.m_value;
    return Value.m_hasValue;
}
template <typename T>
Nullable<T>::Nullable() { }
template <typename T>
Nullable<T>::Nullable(std::nullptr_t nullpointer) { (void)nullpointer; }
template <typename T>
Nullable<T>::Nullable(const T &value)
    : Value(value) { }
template <typename T2>
bool operator==(const Nullable<T2> &op1, const Nullable<T2> &op2)
{
    if (op1.Value.m_hasValue != op2.Value.m_hasValue)
        return false;
    if (op1.Value.m_hasValue)
        return op1.Value.m_value == op2.Value.m_value;
    else
        return true;
}
template <typename T2>
bool operator==(const Nullable<T2> &op, const T2 &value)
{
    if (!op.Value.m_hasValue)
        return false;
    return op.Value.m_value == value;
}
template <typename T2>
bool operator==(const T2 &value, const Nullable<T2> &op)
{
    if (!op.Value.m_hasValue)
        return false;
    return op.Value.m_value == value;
}
template <typename T2>
bool operator==(const Nullable<T2> &op, std::nullptr_t nullpointer)
{
    (void)nullpointer;
    return !op.Value.m_hasValue;
}
template <typename T2>
bool operator==(std::nullptr_t nullpointer, const Nullable<T2> &op)
{
    (void)nullpointer;
    return !op.Value.m_hasValue;
}
template <typename T2>
bool operator!=(const Nullable<T2> &op1, const Nullable<T2> &op2)
{
    if (op1.Value.m_hasValue != op2.Value.m_hasValue)
        return true;
    if (op1.Value.m_hasValue)
        return op1.Value.m_value != op2.Value.m_value;
    else
        return false;
}
template <typename T2>
bool operator!=(const Nullable<T2> &op, const T2 &value)
{
    if (!op.Value.m_hasValue)
        return true;
    return op.Value.m_value != value;
}
template <typename T2>
bool operator!=(const T2 &value, const Nullable<T2> &op)
{
    if (!op.Value.m_hasValue)
        return false;
    return op.Value.m_value != value;
}
template <typename T2>
bool operator!=(const Nullable<T2> &op, std::nullptr_t nullpointer)
{
    (void)nullpointer;
    return op.Value.m_hasValue;
}
template <typename T2>
bool operator!=(std::nullptr_t nullpointer, const Nullable<T2> &op)
{
    (void)nullpointer;
    return op.Value.m_hasValue;
}
template <typename T>
const Nullable<T> & Nullable<T>::operator=(const Nullable<T> &value)
{
    Value.m_hasValue = value.Value.m_hasValue;
    Value.m_value = value.Value.m_value;
    return *this;
}
template <typename T>
const Nullable<T> & Nullable<T>::operator=(const T &value)
{
    Value.m_hasValue = true;
    Value.m_value = value;
    return *this;
}
template <typename T>
const Nullable<T> & Nullable<T>::operator=(std::nullptr_t nullpointer)
{
    (void)nullpointer;
    Value.m_hasValue = false;
    Value.m_value = T();
    return *this;
}
template <typename T>
T * Nullable<T>::operator->()
{
    return &Value.m_value;
}
template <typename T>
const T * Nullable<T>::operator->() const
{
    return &Value.m_value;
}
template <typename T>
T & Nullable<T>::operator*()
{
    return Value.m_value;
}
template <typename T>
const T & Nullable<T>::operator*() const
{
    return Value.m_value;
}
I tested it in gcc, clang and VS15 with the following:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
  (void)argc;
  (void)argv;
    Nullable<int> ni1;
    Nullable<int> ni2 = nullptr;
    Nullable<int> ni3 = 3;
    Nullable<int> ni4 = 4;
    ni4 = nullptr;
    Nullable<int> ni5 = 5;
    Nullable<int> ni6;
    ni6 = ni3;
    Nullable<int> ni7(ni3);
    //Nullable<int> ni8 = NULL; // This is an error in gcc/clang but it's ok in VS12
    cout << (ni1 == nullptr ? "True" : "False") << endl; // True
    cout << (ni2 == nullptr ? "True" : "False") << endl; // True
    cout << (ni2 == 3 ? "True" : "False") << endl; // False
    cout << (ni2 == ni3 ? "True" : "False") << endl; // False
    cout << (ni3 == 3 ? "True" : "False") << endl; // True
    cout << (ni2 == ni4 ? "True" : "False") << endl; // True
    cout << (ni3 == ni5 ? "True" : "False") << endl; // False
    cout << (ni3 == ni6 ? "True" : "False") << endl; // True
    cout << (ni3 == ni7 ? "True" : "False") << endl; // True
    //cout << ni1 << endl; // Doesn't compile
    //cout << ni3 << endl; // Doesn't compile
    cout << ni3.Value << endl; // 3
    //cout << ni1.Value << endl; // Throw exception
    //cout << ni2.Value << endl; // Throw exception
    //ni3.Value = 2; // Doesn't compile
    cout << sizeof(ni1) << endl; // 8 on VS15
    return 0;
}