Интерфейс, все свойства и гарантии должны соответствовать std::variant. Специализацию std::hash писать не надо.
По аналогии с заданием optional, требуется по возможности сохранять тривиальности для special member functions. Также стоит уделить внимание правильности расстановки noexcept.
Обратите внимание на описание на cppreference для converting конструктора/operator=, которое прямо говорит, как их реализовывать. Такой код должен работать ожидаемым образом:
variant<string, bool> x = "abc"; // holds stringНо проблема в том, что указатель char const* приводится как к bool, так и к string . Изначально для этого в стандарте сделали небольшой "костыль" в P0608R3, по сути обработав специально ситуацию с конвертацией к bool (см. статью). Это иногда ведёт себя неожиданным образом, но пример выше благодаря такому работает.
Потом конверсию к bool признали narrowing: P1957R2, а такие конверсии запрещены в константных выражениях. В том же предложении убрали "костыль" для конструктора variant'а: теперь то, что отсекалось им, должно отсекаться из-за narrowing conversion, и он больше не нужен.