2010-09-04 89 views
20

为什么这个编译失败? (克++ - 4.5)C++模板函数的地址

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

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

EDIT:这里是一个变通:

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 )p =&h ;' – Puppy 2010-09-04 09:53:30

+0

至少可以和G ++ 4.6一起使用。 – Maister 2010-09-12 10:38:17

+0

@DeadMG:如果没有“auto”,甚至不需要typedef,'void(* p)()=&h ;'也会编译。 – doc 2010-09-12 15:34:47

回答

13

在C++ 0x中,这是保证工作。然而,在C++ 03中,这不起作用(即初始化部分),有些编译器显然不支持它。另外,我记得C++ 0x的写法并不清楚&h<int>是什么,当它是一个函数模板的参数并且推导出相应的参数(这是auto被转换为概念性的)。然而,它的意图是有效的。见this defect report他们在那里设计的措辞,“尼科Josuttis”的例子和他们的最后一个例子。

还有另一个规则,措辞强制执行但编译器没有正确执行。例如,see this clang PR

0

它不编译,因为 'P' 的类型是未知的编译器,其是必须的在C++不像其他一些语言。

尝试

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

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

'auto'关键字用于自动类型扣除。一个C++ 0x功能。 – dirkgently 2010-09-04 09:39:34

+0

好的,但在我的真实代码中,h取决于U和其他模板需要很多其他参数,我不想全部指定它们,因为编译器应该知道p的类型。 – Thomas 2010-09-04 09:40:43

+1

@dirkgenly:哦。我仍然在C++ 03其中'自动'用于自动变量 – Chubsdad 2010-09-04 09:41:29

0

尝试

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

因为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? 

海合会h<int>简直就像重载h函数依赖于T参数无尽的替代品。有问题的代码是O.K.做到以下几点:

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

(这就是为什么我没有得到通过typedef“变通”)

,因为我以为OP想用C++ 11 auto通过关键字标签的建议,我静态铸造了h<int>void(*)(),这是一种无操作,只是为了欺骗gcc,因为它无法正确处理模板化函数和auto

函数void h<int>()void h<float>()当然应该被当作具有相同指针类型的不同函数处理,而不是h函数的超载版本。实例化时,他们应该表现得像void hInt()void hFloat(),你应该能够使用自动喜欢这里:

void hInt() 
{ 
} 

void hFloat() 
{ 
} 

auto p = hInt; 
p = hFloat; 

但由于某些原因海合会他们喜欢的h重载版本。

请给出downvotes的原因。

+0

我不是downvoter :)无论如何,我不知道你的逻辑理解:因为你是static_casting编译时间已知的类型,有什么用于汽车? – Francesco 2010-09-12 10:22:08

+0

@Francesco:没有转换gcc会抛出一个错误“语句无法解析重载函数的地址”。在重载函数的情况下(例如'void h(int)'和'void h(float)'),您将得到相同的错误,在这种情况下,编译器在找到'&h'语句时无法确定选择哪个版本。出于某种原因(我认为这是模板参数发现的事情),模板化函数的处理方式与重载的函数相同。在使用static_cast之后,就像在重载函数的情况下一样,它开始编译。 'auto'用于推导'p'类型。 – doc 2010-09-12 15:24:42

+0

@Francesco:他们用'typedef'获得了与static_cast相同的结果。我以为他想要C++ 0x'auto'关键字... – doc 2010-09-12 15:32:35