https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82171
Daniel Krügler <daniel.kruegler at googlemail dot com> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |daniel.kruegler@googlemail. | |com --- Comment #2 from Daniel Krügler <daniel.kruegler at googlemail dot com> --- (In reply to Robert Douglas from comment #1) > I came about this, transitioning from habits using SFINAE. I have just > realized I can simplify it to: > template<typename T> > concept bool MapLike = requires(T t) { > {t[typename T::value_type::first_type{}]} > -> typename T::value_type::second_type; > }; IMO a better approach imposing less unnecessary constraints (such as list-initialization) would be something along the lines of: template<typename T> concept bool MapLike = requires(T t, typename T::value_type::first_type ft) { {t[ft]} -> typename T::value_type::second_type; }; > and bypass the declval, altogether. Question, though, does anything forbid > declval in this context? Technically the error results because the definition (and not only the declaration) of std::declval<typename T::value_type::first_type>() had been instantiated here, because it seems to be considered as odr-used. But according to [expr.prim.req] p2: "Expressions appearing within a requirement-body are unevaluated operands (Clause 8)." and following [expr] p8: "In some contexts, unevaluated operands appear (8.1.7, 8.2.8, 8.3.3, 8.3.7, 10.1.7.2, Clause 17). An unevaluated operand is not evaluated. [Note: In an unevaluated operand, a non-static class member may be named (8.1) and naming of objects or functions does not, by itself, require that a definition be provided (6.2). An unevaluated operand is considered a full-expression (4.6). — end note]" As I understand it, this wording should allow using std::declval within the requirement-body as you did it without causing it being considered odr-used, so the current behaviour looks like a bug to me.