我想出了以下问题(下面的代码):
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编译。
这似乎是合法代码,但我真的不明白为什么。
如果有人能解释,我会很感激。
假设它是合法的,有没有办法可以用仿函数做类似的事情?
答案 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;
}