According to C++23 what is FTDecay<int()&>
?
template <class Signature>
struct Decompose;
template <class T>
struct Decompose<void(T)> {
using Type = T;
};
template <class T>
using FTDecay = typename Decompose<void(T)>::Type;
FTDecay<int()&> x = "Hello";
In current MSVC, Clang and GCC implementations the last line above generates error messages that mention an ill-formed type int (*)() &
(demo). GCC says:
error: cannot convert 'const char*' to 'FTDecay<int() &>' {aka 'int (*)() &'}
in initialization
P0172r0 says it is ill-formed (diagnostic required) to form a reference or a pointer to an abominable function type. The paper introduces this term; it means a function type followed by a cv-ref qualifier. Accordingly, using X = int (*)() &;
is rejected by all compilers (demo).
- [...] After determining the type of each parameter, any parameter of type “array of
T
” or of function typeT
is adjusted to be “pointer toT
”. [...]
- [Note 1: [...] Forming a function pointer type is ill-formed if the function type has cv-qualifiers or a ref-qualifier; see [dcl.fct]. [...]]
This is a non-normative note, but is based on [dcl.fct]p10
- A function type with a cv-qualifier-seq or a ref-qualifier (including a type named by typedef-name ([dcl.typedef], [temp.param])) shall appear only as:
- the function type for a non-static member function,
- the function type to which a pointer to member refers,
- the top-level function type of a function typedef declaration or alias-declaration,
- the type-id in the default argument of a type-parameter ([temp.param]), or
- the type-id of a template-argument for a type-parameter ([temp.arg.type]).
... Where none of those bullets are "the type pointed to by a pointer type" or similar.
Therefore, void(T)
adjusts T
which has function type void() &
to "pointer to void() &
", which is ill-formed.
This would be a SNIFE-able error, but FTDecay<int()&>
is ill-formed because Decompose<void(T)>
is ill-formed. This is a compiler bug in Clang and GCC that a pointer to ref-qualified function type is formed in the first place and a bug in MSVC that the error isn't early enough (it seems to just pick the default specialization, and doesn't adjust the function type to a pointer to make it an error: https://godbolt.org/z/M9nEzoeET)