Reinventing std::optional
Prefer value type semantic

Try to make classes default constructible and equality comparable whenever this makes sense. Currently your Optional class doesn't fulfil neither. The following code will not compile

class A { int a; A() = delete; };

int main()
{
  Optional&lt;A&gt; i;
}


Even though it might make sense to have an optional. Also consider this example

struct B { B() { /* insert something super long */ } }:

int main()
{
  Optional&lt;B&gt; opt_b; // this line takes really long!
}


Here is an example of how to use std::aligned_storage to use uninitialised memory. I think this could help you as well.

Do not return by value if you can

The line

T get() const { return val_; }


Makes a copy of T while returning val_. Imagine val_ is a very big std::string. This could be very expensive in code which calls get() multiple times. If you want read-only access, prefer to use

const T&amp; get() const&amp; noexcept { return val_; }


instead.

Make use of move assignments

Currently you have to copy values into your optional. But what, if you just want to move something big that you want to return from a function? You 
need to add constructors for rvalue-Ts.

Optional(T&amp;&amp; value)
 : val_{std::move(value)}
 , is_set_{true} {}