模板函数参数中的自动模板特化

时间:2013-07-16 19:05:05

标签: c++ templates specialization

我想出了以下问题(下面的代码):

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;
}

我的问题是它用vc ++ 8(VS2005)和GCC,CLang编译(在Ubuntu 12.04上) 但无法使用vc ++ 2008 express编译。

这似乎是合法代码,但我真的不明白为什么。

如果有人能解释,我会很感激。

假设它是合法的,有没有办法可以用仿函数做类似的事情?

3 个答案:

答案 0 :(得分:2)

我假设您打算将func用于printname(反之亦然)。

对于它的价值,我相信这段代码是合法的,而VS2008(以及VS2010;我目前没有VS2012方便)的事实拒绝它看起来像编译器错误。

Re:类似于仿函数的东西 - 看看这是否适合你:

#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;
}

答案 1 :(得分:0)

我不确定这个问题是为什么它适用于大多数编译器,或者为什么它在VS2008中失败。如果问题是前者,我们可以讨论这个的简化版本:

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

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

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

指向函数的指针在语言中有点特殊,因为相同的名称可以引用不同的重载。当在代码中使用函数的名称时,编译器无法确定哪个重载由其自身确定,因此它将使用表达式的 target 来确定它。在g(f)的情况下,由于g函数采用void (std::string const&)类型的函数,因此它将f解析为f<std::string>,而在{1}}的情况下fn初始化编译器将解析为专门化f<double>

请注意,这是该语言的非常常用的功能:

std::cout << std::endl;

名称std::endl指的是模板:

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

编译器发现这是在类型为std::cout的对象basic_ostream<char,char_traits<char>>上调用的,并且唯一与operator<<调用匹配的特殊化是charT == char }和traits == char_traits<char>并选择正确的专业化。

答案 2 :(得分:0)

在Visual Studio 2010上,解决方案既简单又精巧。您只需在行<int>中的printname之后添加applyfunc(a,printname<int>);即可。编译器需要帮助确定要使用的模板类型。

#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;
}