Today, I was trying to perform a type switch on whether some class has the nested type reverse_iterator or not. I found on these fora some working solution, which is the following one:
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);
};
This class works just fine if I simply check the condition from the main, however, I also wrote that little function, which cause some problems.
template<typename T>
void foo(T&& iter)
{
std::cout << typeid(T).name() << std::endl;
std::cout << is_reverse_iterable<T>::value << std::endl;
}
Here is the main that causes me some problems:
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;
}
As std::vector<int> contains the nested type name reverse_iterator, one would think – or at least, I would think – that is_reverse_iterable<vector<int>>::value would return true wherever I put it. But it’s not the case. Here is the result of the main above:
St6vectorIiSaIiEE
1
St6vectorIiSaIiEE
0
When called from the main, the struct is_reverse_iterable recognized the name reverse_iterator in vector<int>, but it did not do so when called from foo. Actually, I have no idea why, and I would like someone to please explain to me what the problem is 🙂
P.S. : I use MinGW g++ 4.7.1 to compile, with the option -std=c++11.
The problem is that when you call
foo(v), it is deduced thatTis of typestd::vector<int>&(an lvalue-reference), sotypename T::reverse_iteratorwill not compile. You can easily check it yourself:Yields:
The solution is simple: remove the reference before you start the SFINAE, e.g.