作为模板参数的引用限定成员函数?

9

这在clang 3.3中可以编译成功:

template <typename T>
struct M;

template <typename R, typename C, typename... A>
struct M <R (C::*)(A...)> { };

template <typename R, typename C, typename... A>
struct M <R (C::*)(A...) &> { };

但在gcc 4.8.1中失败:

[...] error: redefinition ofstruct M <R (C::*)(A ...)>’
 struct M <R (C::*)(A...) &> { };
        ^
[...] error: previous definition ofstruct M <R (C::*)(A ...)>’
 struct M <R (C::*)(A...)> { };
        ^

在不同的上下文中使用时,这会导致各种意外的编译器行为,例如崩溃或内部编译器错误。
我了解到,在标准中,ref-qualified成员函数被称为“rvalue引用* this”(N2439),并且被gcc 4.8.1支持
问题在于将它们用作模板参数时,gcc似乎无法区分ref-qualified和普通成员函数类型。
clang的std库实现似乎能够检测是否支持此功能。
__has_feature(cxx_reference_qualified_functions)

那么,ref-qualified函数的使用是标准的还是语言扩展?

1个回答

3
根据8.3.5 [dcl.fct]第6段(我在引用的文本中添加了一些突出显示):
“返回类型,参数类型列表,ref-qualifier和cv-qualifier-seq,但不包括默认参数(8.3.6)或异常说明(15.4),是函数类型的一部分。”
也就是说,ref-qualifier肯定是类型的一部分。根据8.4.1 [dcl.fct.def.general]第5段,您可以创建包括ref-qualifiers的指向成员的指针:
“cv-qualifier-seq或ref-qualifier(或两者都可以)可以是非静态成员函数声明、非静态成员函数定义或仅指向成员函数的指针(8.3.5);请参见9.3.2。”
没有特定的限制,指向具有ref-qualifier的成员函数的指针不能用作非类型模板参数。也就是说,我认为您尝试使用的部分特化应该有效。然而,对于clang和gcc来说,支持ref-qualifiers是一个相当新的功能,即可能并未解决所有边角情况。我尝试了以上代码片段,使用了最近版本的gcc(20130811)和clang(trunk 190769),两者都编译了代码。当然,这个片段实际上并没有做任何事情,我也没有试图滥用这个功能。我猜您只是触发了一些编译器错误,并且我相信这两个项目都会欣赏对他们最新快照的错误报告。

非常清楚,非常感谢!我已经对这个问题失去了希望 :-) 所以当我更新gcc时,我应该期望这个功能能够正常工作,对吗?目前,我已经在gcc中禁用了代码的这一部分。从上面提到的clang的检测结果来看,我怀疑已知道gcc的支持只是部分的。 - iavr
@iavr:clang的检测机制可以检测到该功能是否在clang中可用!我不确定其他编译器是否已经支持相同的检测机制。请注意,我尝试的编译器并非发布版本:它们只是我从各自的代码库中获取并编译的最新版本。当这些版本(gcc-4.9.0和clang-3.4)发布时,我无法预测。 - Dietmar Kühl

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