Проблема с выбором шаблона для подстановки на gcc 5
Желаемое поведение: Корректная работа функции validate.
Проблема: На версиях компилятора gcc < 9 происходит подстановка шаблона-заглушки вместо ожидаемого (т.е. не выполняется проверка условия). При этом, если раскомментировать cout (тем самым явно инстанцируя шаблон) валидатор отработает корректно. На версиях gcc 9, а так же clang (проверял на 4 и 9), код работает корректно (даже без явного инстанцирования). В чем может быть проблема?
#include <iostream>
#include <type_traits>
#include <cstdint>
struct SomeParam
{
static constexpr uint8_t default_value = 0;
static constexpr uint8_t min = 0;
static constexpr uint8_t max = 1;
};
template <typename T, typename = void>
struct has_max : std::false_type {};
template <typename T>
struct has_max<T, decltype (std::declval<T>().max, void())> : std::true_type {};
template <typename T, typename U>
static constexpr typename std::enable_if< has_max<T>::value, bool >::type check_max(U val)
{
return val <= T::max;
}
template <typename T, typename U>
static constexpr typename std::enable_if< !has_max<T>::value, bool >::type check_max(U)
{
return true;
}
template <typename Param, typename ValueType>
constexpr bool validate(ValueType value)
{
return check_max<Param>(value);
}
int main(int argc, char* argv[])
{
uint8_t var = 10;
//std::cout << has_max<SomeParam>::value;
if ( validate<SomeParam>(var) )
printf("HELLO");
return 0;
}
Ответы (1 шт):
Автор решения: user7860670
→ Ссылка
В decltype (std::declval<T>().max, void()) как-то слишком много всего наворочено:
std::declvalиспользуется без подключения заголовочного файлаutility- доступ к статическому полю через оператор точка у rvalue
- оператор запятой, молча отбрасывающий левое значение
- инстанцирование void
Более простой вариант c decltype(static_cast<void>(T::max)) работает везде:
https://godbolt.org/z/fGSYtS
#include <type_traits>
#include <utility>
template <typename T, typename = void> struct
has_min: ::std::false_type {};
template <typename T> struct
//has_min<T, decltype(::std::declval<T>().min, void())>: ::std::true_type {};
has_min<T, decltype(static_cast<void>(T::min))>: ::std::true_type {};
template <typename T, typename U> constexpr
typename ::std::enable_if<has_min<T>::value, bool>::type
check_min(U val)
{
return T::min <= val;
}
template <typename T, typename U> constexpr
typename ::std::enable_if<! has_min<T>::value, bool>::type
check_min(U)
{
return false;
}
template <typename Param, typename ValueType> constexpr
bool validate(ValueType value)
{
return check_min<Param>(value);
}
struct Foo1 { static constexpr int min = 5; };
struct Foo2 { static constexpr int min = 5; };
struct Foo3 { };
struct Foo4 { };
constexpr int value{6};
static_assert(has_min<Foo1>::value, "");
static_assert(validate<Foo1>(value), "");
//static_assert(has_min<Foo2>::value, "");
static_assert(validate<Foo2>(value), "");
static_assert(! has_min<Foo3>::value, "");
static_assert(! validate<Foo3>(value), "");
//static_assert(! has_min<Foo4>::value, "");
static_assert(! validate<Foo4>(value), "");