Я пытаюсь добавить специализации для случая, когда мой вариант имеет любой из int
, float
, bool
и другие в качестве аргументов шаблона.
Моя попытка до сих пор :
#include <iostream>
#include <variant>
#include <string>
#include <type_traits>
template<typename... Types>
struct variant : std::variant<Types...> {
using std::variant<Types...>::variant;
template<typename T>
const T& get() const { return std::get<T>(*this); }
#define VARGET(X) typename std::enable_if<(std::is_same<Types, X>::value || ... ), X>::type get_##X() const { return get<X>(); }
VARGET(int)
VARGET(float)
VARGET(double)
VARGET(bool)
using std_string = std::string;
VARGET(std_string)
};
int main()
{
variant<int, float, bool> var = 3;
std::cout << var.get_int() << std::endl;
variant<int, float, bool> var2 = 0.1f;
std::cout << var2.get_float() << std::endl;
return 0;
}
Но на g cc 9 это выдает ошибку:
error: failed requirement 'std::is_same<int, double>::value || std::is_same<float, double>::value || std::is_same<bool, double>::value'; 'enable_if' cannot be used to disable this declaration
Почему это меня смущает :
Из моего понимания SFINAE, когда один из аргументов является одним из указанных типов, шаблон макроса оценивается следующим образом: (для примера int)
std::enable_if<(std::is_same<Types, int>::value || ... ), int>::type
оценивается как int
таким образом выражение становится int get_int() const { std::get<int>(*this) }
И если оно не относится к одному из указанных типов:
std::enable_if<(std::is_same<Types, size_t>::value || ... ), size_t>::type
вычисляется в ничто
, поэтому выражение становится get_size_t() const { std::get<size_t>(*this) }
Это недопустимый синтаксис, потому что функция не имеет возвращаемого типа, но из-за SFINAE она все равно должна компилироваться из-за других подстановок X, создающих допустимый синтаксис.
Что не так с мой код, и есть ли способ получить желаемый результат?
Спасибо.