模板函数参数中的自动模板专业化

Automatic Template Specialization in Template Function Argument

本文关键字:专业化 函数 参数      更新时间:2023-10-16

我遇到了以下问题(下面的代码):

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++2008express进行编译。

这似乎是法律法规,但我真的不明白为什么。

如果有人能解释,我将不胜感激。

假设它是合法的,有什么方法可以对函子做类似的事情吗?

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

值得一提的是,我相信这段代码是合法的,而VS2008(还有VS2010;我现在没有VS2012)拒绝它的事实看起来像是一个编译器错误。

回复:与函子类似的东西-看看这是否对你有用:

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

我不确定问题是为什么它在大多数编译器中都能工作,还是为什么它在VS2008中失败。如果问题是前者,我们可以讨论一个简化版本:

template <typename T>
void f(T const &) {}
void g(void (*fn)(std::string const&) {}
g(f); // compiles
void (*fn)(double const &) = f;

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

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

std::cout << std::endl;

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

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

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

在Visual Studio 2010上,该解决方案简单而微妙。您只需在applyfunc(a,printname<int>);行的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;
}