This compiles fine in 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...) &> { };
but fails in gcc 4.8.1:
[...] error: redefinition of ‘struct M <R (C::*)(A ...)>’
struct M <R (C::*)(A...) &> { };
^
[...] error: previous definition of ‘struct M <R (C::*)(A ...)>’
struct M <R (C::*)(A...)> { };
^
When used in different contexts, this results in all sorts of unexpected compiler behaviour like crashing or internal compiler errors.
I understand ref-qualified member functions are referred to as "rvalue references for *this" (N2439) in the standard, and are supported by gcc 4.8.1.
The problem here is to use them as template arguments, where gcc does not appear to discriminate between a ref-qualified and an ordinary member function type.
clang's implementation of the std library seems to detect whether this feature is supported by
__has_feature(cxx_reference_qualified_functions)
So, is this use of ref-qualified functions standard, or a language extension?
According to 8.3.5 [dcl.fct] paragraph 6 (I added some highlightening to the quoted text):
The return type, the parameter-type-list, the ref-qualifier, and the cv-qualifier-seq, but not the default arguments (8.3.6) or the exception specification (15.4), are part of the function type.
That is, the ref-qualifier is certainly part of the type. Further according to 8.4.1 [dcl.fct.def.general] paragraph 5 you can create pointer-to-members including the ref-qualifiers:
A cv-qualifier-seq or a ref-qualifier (or both) can be part of a non-static member function declaration, non-static member function definition, or pointer to member function only (8.3.5); see 9.3.2.
There is no specific restriction that pointer to member functions with ref-qualifier cannot be used as non-type template arguments. That is, I think the partial specialization you tried to use should work. However, support for ref-qualifiers is a fairly new feature in both clang and gcc, i.e., probably not all corner cases have been ironed out. I tried the snipped above with fairly recent snapshots of both gcc (20130811) and clang (trunk 190769) and both compiled the code OK. Of course, this snippet doesn't really do anything and I didn't try to abuse this feature. I would guess you just triggered a few compiler bugs and I'm sure that both projects would appreciate error reports against their latest snapshots.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With