ComplexRobot
ComplexRobot

Reputation: 45

SFINAE not working on Visual Studio 2010 for std::is_pointer

The SFINAE principle isn't working for what seems really simple in Visual Studio 2010.

#include <type_traits>
#include <iostream>

struct MyStruct
{
  int value;
  MyStruct(int value = 42) : value(value) { }
  const int& getInt() const { return value; }
};

template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
  typename std::enable_if
  <std::is_pointer<decltype(*iter)>::value, const int&>::type
{
  return (*iter)->getInt();
}

template <typename ITER_TYPE>
auto getIteratorInt(ITER_TYPE iter) ->
  typename std::enable_if
  <!std::is_pointer<decltype(*iter)>::value, const int&>::type
{
  return iter->getInt();
}

int main(void)
{
  MyStruct gloryInt;
  MyStruct* gloryIntPtr = &gloryInt;
  std::cout << getIteratorInt(gloryIntPtr) << std::endl;
  std::cout << getIteratorInt(&gloryIntPtr) << std::endl;
  return 0;
}

My intention is to use std::enable_if to compile the correct template overload based on the SFINAE principle. (The function without the existing return type will be ignored, and the other one will be compiled.) That way, you can use a pointer or a double pointer to an object, and the direct object will still be what is accessed.

I get the following compilation error:

main.cpp(14): error C2039: 'type' : is not a member of 'std::tr1::enable_if<_Test,_Type>'
          with
          [
              _Test=false,
              _Type=const int &
          ]
main.cpp(17): error C3646: 'type' : unknown override specifier

Well, this is a really obvious error to have if SFINAE wasn't employed. Is there any way to get the intended functionality in Visual Studio 2010?

Upvotes: 1

Views: 846

Answers (1)

Potatoswatter
Potatoswatter

Reputation: 137830

Heh, should have checked your profile page before updating the other answer.

The type decltype( * iter ) refers to int const *const &, which is a reference to a pointer, not a "bare" pointer. Therefore std::is_pointer returns an unexpected result. There are two ways to solve this:

  • Use std::iterator_traits from C++03, which I prefer:

    typename std::iterator_traits< ITER_TYPE >::value_type
    
  • Use the std::decay metafunction which strips out references decltype might add to reflect the value category of the expression

    typename std::decay< decltype( * iter ) >::type
    

Upvotes: 2

Related Questions