user2588533
user2588533

Reputation: 1

Automatic Template Specialization in Template Function Argument

I came up with the following problem (code below):

template<class T>
void printname(const T& t){std::cout<<t<<std::endl;}

template<class T>
void applyfunc(const T& t, void (*f)(const T& )){(*f)(t);}
int main(){
    const int a=1;
    applyfunc(a,printname);
    getchar();
    return 0;
}

My problem is that it compiles with vc++8(VS2005), and GCC, CLang (on Ubuntu 12.04) but fails to compile with vc++ 2008 express.

It seems to be legal code but I don't really get why.

If anyone could explain it I'd appreciate it.

Supposing it is legal, is there any way that something similar could be done with functors?

Upvotes: 0

Views: 393

Answers (3)

Nathan
Nathan

Reputation: 8940

On Visual Studio 2010, the solution is easy yet subtle. You simply need to add <int> after printname in the line applyfunc(a,printname<int>);. The compiler needs help figuring out the template type to use.

#include <iostream>

struct printname
{
   template<class T>
   void operator()(const T& t)
   {
      std::cout << t << std::endl;
   }
};

template<class T, class F>
void applyfunc(const T& t, F f)
{
   f(t);
}

int main()
{
  const int a=1;
  applyfunc(a, printname<int>);      // Add <int> here
  return 0;
}

Upvotes: 0

I am not sure as of whether the question is why it works in most compilers or why it fails in VS2008. If the question is the former, we can discuss a simplified version of this:

template <typename T>
void f(T const &) {}

void g(void (*fn)(std::string const&) {}

g(f); // compiles
void (*fn)(double const &) = f;

Pointers to functions are a bit special in the language, since the same name can refer to different overloads. When the name of a function is used in code, the compiler cannot determine which of the overloads is determined by itself, so it will use the target of the expression to determine this. In the case of g(f), since the g function takes a function of type void (std::string const&), it will resolve f to mean f<std::string>, while in the case of the initialization of fn the compiler will resolve to the specialization f<double>.

Note that this is a very commonly used feature of the language:

std::cout << std::endl;

The name std::endl refers to a template:

template <class charT, class traits>
basic_ostream<charT,traits>& endl(basic_ostream<charT,traits>& os);

The compiler sees that this is being called on the object std::cout, of type basic_ostream<char,char_traits<char>>, and that the only specialization that matches the call to operator<< is that where charT == char and traits == char_traits<char> and picks the correct specialization.

Upvotes: 0

Igor Tandetnik
Igor Tandetnik

Reputation: 52471

I assume you meant to use func for printname (or vice versa).

For what it's worth, I believe this code to be legal, and the fact that VS2008 (and also VS2010; I don't have VS2012 handy at the moment) rejects it looks like a compiler bug.

Re: something similar with functors - see if this does it for you:

#include <iostream>

struct printname {
  template<class T>
  void operator()(const T& t) { std::cout<<t<<std::endl; }
};

template<class T, class F>
void applyfunc(const T& t, F f) { f(t); }

int main(){
  const int a=1;
  applyfunc(a, printname());
  return 0;
}

Upvotes: 2

Related Questions