C++模板函数的地址

21

为什么这段代码无法编译通过?(g++-4.5)

template < typename U >
static void h () {
}

int main () {
  auto p = &h<int>; // error: p has incomplete type
}

编辑:这里有一个解决方法:

template < typename U >
static void h () {
}

int main () {
  typedef decltype (&h<int>) D;
  D p = &h<int>; // works
}

1
可以在Visual Studio 2010上编译通过,很可能是GCC的小故障。你可以尝试decltype(&h<int>) p = &h<int>; - Puppy
@DeadMG:如果没有“auto”,甚至不需要typedef,void (*p)() = & h<int>;也可以编译。 - mip
3个回答

14
在C++0x中,这被保证可以工作。然而,在C++03中,这并没有起作用(即初始化部分),一些编译器显然还不支持它。
此外,我记得C++0x的措辞并不清楚当&h<int>是函数模板的参数并且相应的参数被推导时会发生什么(这就是auto的概念翻译)。然而,意图是它是有效的。请参见这个缺陷报告,其中他们设计了措辞、"Nico Josuttis"的示例和他们的最终示例。
还有一个规则是措辞强制执行但编译器没有正确实现。例如,请参阅此clang PR

0

它无法编译,因为'p'的类型对于编译器来说是未知的,在C++中这是必须的,而其他一些语言则不需要。

尝试

template < typename U > 
static void h () { 
} 

int main () { 
  auto void (*p)() = &h<int>; 
} 

1
auto 关键字用于自动类型推导。这是 C++0x 的一个特性。 - dirkgently
好的,但在我的实际代码中,h会根据U和其他模板使用许多其他参数,我不想指定它们全部,因为编译器应该知道p的类型。 - Thomas
1
@dirkgenly:哦,我还停留在C++03阶段,其中'auto'是用于自动变量的。 - Chubsdad
问题可能与C++ 0x的“auto”有关,它应该能够自动确定类型,即“旧”的“这是堆栈变量”- auto。 - peterchen
1
这里“auto”是纯粹的无意义。 - mip
显示剩余2条评论

0

尝试

 auto p  = static_cast<void(*)()>(& h<int>);

因为gcc将模板函数视为重载函数。从gcc的角度来看,就像你有h(int param)h(float param)一样——编译器该选择哪一个?

我注意到在旧版本的gcc中存在问题,但我会尝试更详细地解释它。GCC无法推断类型,因为模板函数被视为重载函数。基本上就像你有以下内容:

void h(int)
{
}

void h(float)
{
}

void (*p)(int) = & h;  //ok
void (*p)(float) = & h; //ok
auto p = & h; //error: which version of h?

对于gcc而言,h<int>就像是一个重载的h函数,具有无数取决于T参数的替代方案。使用问题中提供的代码,可以这样做:

void (*p)() = & h<int>;

这就是为什么我没有被typedef“work-around”的原因。

正如我所想,OP想要使用c++11的auto关键字,正如标签所建议的那样,我将h<int>静态转换为void(*)(),这种操作有点像无操作,只是为了欺骗gcc,因为它不能正确处理模板函数和auto

函数void h<int>()void h<float>()当然应该被视为具有相同指针类型的不同函数,而不是h函数的重载版本。当实例化时,它们应该像void hInt()void hFloat()一样运行,并且您应该能够在此处使用auto:

void hInt()
{
}

void hFloat()
{
}

auto p = hInt;
p = hFloat;

但是对于gcc来说,它们就像是h的过载版本,原因不明。

请给出负评的原因。


我不是那个踩你的人 :) 无论如何,我不确定是否理解你的逻辑:由于你正在将 static_cast 转换为编译时已知类型,那么 auto 有什么用处呢? - Francesco
@Francesco:如果没有强制类型转换,gcc会抛出一个错误“语句无法解析重载函数的地址”。在重载函数的情况下(例如void h(int)void h(float)),编译器无法确定在找到&h语句时选择哪个版本,因此也会出现相同的错误。由于某种原因(我认为这与模板参数发现有关),模板化函数被视为重载函数的一种方式。在我像处理重载函数那样使用static_cast之后,它开始编译。auto用于推断p类型。 - mip
@Francesco:他们使用 typedefstatic_cast 得到了相同的结果。我认为他想要 C++0x 的 auto 关键字... - mip
我同意typedef存在相同的问题:你必须手动指定类型,因此自动类型推断的优势就会丧失。 - Francesco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接