0

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?

Nathan
  • 8,093
  • 8
  • 50
  • 76
  • 1
    What error do you get with VS2008 Express? – Praetorian Jul 16 '13 at 19:17
  • Are you asking why VS2008 rejects the code, or why the others accept it? *It seems to be legal code but I don't really get why* Also, I am not sure what *is there any way that something similar could be done with functors?* really means. What is the something similar that you'd like done? – David Rodríguez - dribeas Jul 16 '13 at 19:26
  • @Praetorian: C2896,C2784 cannot use function template void (*)(const T& ) as function argument – user2588533 Aug 11 '13 at 20:00
  • @DavidRodríguez-dribeas: First question: yes, second question was answered by Igor Tandetnik below. – user2588533 Aug 11 '13 at 20:00

3 Answers3

2

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;
}
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • Thanks for the answer. I've only tried the case when the functor itself was templated, and not its member function. Silly me. – user2588533 Aug 11 '13 at 19:38
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.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Thanks for the answer. Since I'd posted my question I've checked the standard, and my code in the post is correct as you've explained. – user2588533 Aug 11 '13 at 19:39
0

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;
}
Nathan
  • 8,093
  • 8
  • 50
  • 76