Raoul Steffen Raoul Steffen - 3 months ago 16
C++ Question

MSVC: explicit template instantiation fails while implicit instantiation succeeds

I just came across a problem with MSVC (Version 12 Update 5):

Explicitly instantiating a template function fails, if that function has an overload which is disabled through SFINAE. However, calling that function (thereby implicity instantiating it) works.

Sample code:

#include <type_traits>

template <typename T>
std::enable_if_t< std::is_integral<T>::value, // test is true for T=int
void> foo( T& ) {}

template <typename T>
std::enable_if_t< std::is_pointer<T>::value, // test is false for T=int
void> foo( T& ) {}

void bar( )
{
int i;
foo( i ); // calls foo( int& ) (obviously), compiles fine
}
template void foo( int& ); // explicit instantiation, throws compiler error


The compiler error I get is
error C2794: 'type' : is not a member of any direct or indirect base class of 'std::enable_if<false,void>'
.
The same code seems to be fine with GCC (apart from missing the main function): live on Ideone.

Is this an MSVC bug? Is there a good way to make these explicit template instantiations?

Answer

The following allows to instantiate the function, making sure it compiles and should (by my understanding) also put it into the .obj-file:

namespace {
  template <typename T>
  void helper( T& A )
  {
    foo( A );
  }

  template void helper( int& );
}

The trick here is, that helper(..) is neither overloadad, nor disabled for any type. Sorting out the disabled overloads is delayed to the 'call' to foo(..) within helper(..), which MSVC succeeds to resolve.

EDIT: As we have seen that other compilers understand my original code, as well as newer versions of MSVC (thanks Niall), I assume it is a bug of my version of MSVC, and consider that part question sufficiently thought over.