Specialize variadic template member function

Viewed 55

Is there a way to get this "fake overloading" argument specialization to work?

#include <iostream>

class Foo
{
public:
  template < typename T, typename ... Args > 
  T* bar (Args&& ... args);
};

template <> 
int* Foo::bar()
{
  std::cout << "int* bar()\n";
  return new int;
}

// error: template-id ‘bar<>’ for ‘double* Foo::bar(double)’ does not match any template declaration
template <> 
double* Foo::bar(double d)
{
  std::cout << "double* bar(" << d << ")\n";
  return new double;
}

int main()
{
  Foo f;
  f.bar<int>();
  f.bar<double>(3.0);
}

One solution would be to actually overload the function, e.g.

class Foo
{
public:
  template < typename T, typename ... Args > 
  T* bar (Args&& ... args);
  template < typename T, typename U > 
  T* bar (U u);
};

but I would prefer to avoid that if possible. I am looking at dozens of allowed combinations of return type and arguments, so overloading is impractical.

I assume some SFINAE magic should make it possible to only enable very specific combinations of return type and arguments, but I feel that I'm probably missing a simpler option.

1 Answers

The parameter type of the specialization double, doesn't match the parameter type of the primary template Args&&, as the error message said.

The primary template is applying forwarding reference, which could instantiate as both lvalue-reference or rvalue-reference. For rvalue-reference (which matches the usage in main()) the specialization should be

template <> 
double* Foo::bar(double&& d)
{
  std::cout << "double* bar(" << d << ")\n";
  return new double;
}
Related