Сегодня я пытался выполнить переключение типов, если какой-то класс имеет вложенный тип reverse_iterator
или нет. На этих форумах я нашел какое-то рабочее решение, а именно:
template<typename T>
struct is_reverse_iterable
{
using yes = uint8_t;
using no = uint16_t;
template<typename U>
static yes& test(typename U::reverse_iterator*);
template<typename>
static no& test(...);
static constexpr bool value = sizeof(test<T>(0)) == sizeof(yes);
};
Этот класс работает просто отлично, если я просто проверяю условие из основного, однако я также написал эту маленькую функцию, которая вызывает некоторые проблемы.
template<typename T>
void foo(T&& iter)
{
std::cout << typeid(T).name() << std::endl;
std::cout << is_reverse_iterable<T>::value << std::endl;
}
Вот главное, что вызывает у меня некоторые проблемы:
int main()
{
using namespace std;
vector<int> v;
cout << typeid(decltype(v)).name() << endl;
cout << is_reverse_iterable<decltype(v)>::value << endl;
foo(v);
return 0;
}
Как std::vector<int>
содержит имя вложенного типа reverse_iterator
можно подумать — или, по крайней мере, я бы подумал — что is_reverse_iterable<vector<int>>::value
вернул бы истину, куда бы я ни положил. Но это не так. Вот результат основного выше:
St6vectorIiSaIiEE
1
St6vectorIiSaIiEE
0
Когда вызывается из основного, структура is_reverse_iterable
узнал имя reverse_iterator
в vector<int>
, но он не сделал этого при вызове из foo
, На самом деле, я понятия не имею, почему, и я хотел бы, чтобы кто-нибудь объяснил мне, в чем проблема 🙂
Постскриптум : Я использую MinGW g ++ 4.7.1 для компиляции с опцией -std = c ++ 11.
Проблема в том, что когда вы звоните foo(v)
, выводится, что T
имеет тип std::vector<int>&
(lvalue-ссылка), так typename T::reverse_iterator
не будет компилироваться. Вы можете легко проверить это самостоятельно:
template<typename T>
void foo(T&& iter)
{
std::cout << typeid(T).name() << std::endl;
std::cout << is_reverse_iterable<T>::value << std::endl;
typename T::reverse_iterator t; // <-- add this line to see what's wrong
}
Урожайность:
3.cpp: In instantiation of ‘void foo(T&&) [with T = std::vector<int>&]’:
3.cpp:40:10: required from here
3.cpp:27:34: error: ‘std::vector<int>&’ is not a class, struct, or union type
Решение простое: удалите ссылку перед запуском SFINAE, например,
static constexpr bool value = sizeof(test<typename std::decay<T>::type>(0))
== sizeof(yes);
Других решений пока нет …