Я думаю, что я столкнулся с ошибкой с шаблоном C++ 11 std :: basic_type.Это ошибка с std :: basic_type
Я использую класс признаков для определения диапазонов перечислений, которые мы имеем в нашей системе. Тогда я могу предоставить общую функцию is_valid.
Я недавно расширил функцию, когда -Wextra был включен, потому что я получал много предупреждений о всегда истинном сравнении.
Когда перечисление имеет неподписанный тип, а его первое значение равно 0, предупреждение было сгенерировано.
Решил, что легко. Но на следующий день некоторые модульные тесты в модулях с использованием функции начались с .
Если вы не укажете базовый тип перечисления, он по-прежнему выбирает правильную реализацию, но как-то возвращает неправильный результат.
Вот минимальный пример (http://ideone.com/PwFz15):
#include <type_traits>
#include <iostream>
using namespace std;
enum Colour
{
RED = 0,
GREEN,
BLUE
};
enum NoProblems : int
{
A,
B,
C
};
enum AlsoOk : unsigned
{
D,
E,
F
};
template <typename Enum> struct enum_traits;
template <> struct enum_traits<Colour>
{
typedef Colour type;
static constexpr type FIRST = RED;
static constexpr type LAST = BLUE;
};
template <> struct enum_traits<NoProblems>
{
typedef NoProblems type;
static constexpr type FIRST = A;
static constexpr type LAST = C;
};
template <> struct enum_traits<AlsoOk>
{
typedef AlsoOk type;
static constexpr type FIRST = D;
static constexpr type LAST = F;
};
#if 0
// This implementation gives you warnings about an always true comparison
// ONLY IF you define the underlying type of your enum, such as Colour.
template <typename Enum>
inline constexpr bool is_valid(Enum e)
{
return e >= enum_traits<Enum>::FIRST && e <= enum_traits<Enum>::LAST;
}
#endif
// So you define the is_valid function like so, to prevent the warnings:
template <typename Enum, typename enable_if<is_unsigned<typename underlying_type<Enum>::type>::value && enum_traits<Enum>::FIRST == 0, int>::type = 0>
inline constexpr bool is_valid(Enum e)
{
return e <= enum_traits<Enum>::LAST;
}
template <typename Enum, typename enable_if<is_signed<typename underlying_type<Enum>::type>::value || enum_traits<Enum>::FIRST != 0, int>::type = 0>
inline constexpr bool is_valid(Enum e)
{
return e >= enum_traits<Enum>::FIRST && e <= enum_traits<Enum>::LAST;
}
int main()
{
Colour c = static_cast<Colour>(RED - 1);
cout << is_valid(c) << endl;
NoProblems np = static_cast<NoProblems>(A - 1);
cout << is_valid(np) << endl;
AlsoOk ao = static_cast<AlsoOk>(D - 1);
cout << is_valid(ao) << endl;
return 0;
}
Что дает выход:
1
0
0
Очевидно, что выход для первого вызова is_valid, должно быть 0/ложь. Так или иначе, перечисление одновременно подписывается и без знака?
Я пропустил какую-то критическую часть документации в стандартной библиотеке относительно шаблонов, которые я использовал?
Это поправимо, выполняя сравнение, как так:
return static_cast<typename std::underlying_type<Enum>::type>(e) <= enum_traits<Enum>::LAST;
Но это не кажется, что должно быть необходимым.
Я попробовал это на GCC 4.8.1, GCC 4.7.3 и 3.2.1 лязгом, все на x86-64