Before rev 225651 (the fix for #66758), the following worked. It no longer does. Not sure if it's legit. template <class From, class To> concept bool ExplicitlyConvertible = requires (From&& f) { static_cast<To>((From&&)f); }; template <class T, class... Args> concept bool Constructible = ExplicitlyConvertible<Args..., T> || requires (Args&&... args) { T{((Args&&)(args))...}; }; template <class T, class...Args> constexpr bool constructible() { return false; } Constructible{T, ...Args} constexpr bool constructible() { return false; } int main() {} Yields: /cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp: In function ‘constexpr bool Constructible()’: /cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp:9:5: error: pack expansion argument for non-pack parameter ‘From’ of concept ‘template <class From, class To> constexpr const bool ExplicitlyConvertible<From, To>’ ExplicitlyConvertible<Args..., T> || ^ /cygdrive/c/Users/eric/Code/cmcstl2/test/iterator.cpp:1:11: note: declared here template< class From, class To > ^
This was introduced by my patch for bug 66092, applying the tentative resolution of core issue 1430 to concepts as well as alias templates. This makes sense to me since they have the same issue of needing to substitute dependent arguments into the template, in this case during normalization. So I think your example is invalid, but it could use some discussion in core.
I think that this is invalid too. There's an expansion from an uninstantiated template argument pack into a pair of template parameters. I think the program must be ill-formed in this case. It's not possible to substitute a single pack through the two parameters declared for ExplicitlyConvertible in order to normalize the constraint. The TS is silent on this, but the resolution should be the same as that of 1430. Andrew Sutton On Fri, Jul 10, 2015 at 10:48 PM, jason at gcc dot gnu.org <gcc-bugzilla@gcc.gnu.org> wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66834 > > --- Comment #1 from Jason Merrill <jason at gcc dot gnu.org> --- > This was introduced by my patch for bug 66092, applying the tentative > resolution of core issue 1430 to concepts as well as alias templates. This > makes sense to me since they have the same issue of needing to substitute > dependent arguments into the template, in this case during normalization. > > So I think your example is invalid, but it could use some discussion in core. > > -- > You are receiving this mail because: > You are on the CC list for the bug.
I was thinking that overloading the Constructible concept would be a conforming way to express this, but it doesn't seems to work. Any clue why? template <class T, class U> concept bool Same = __is_same_as(T, U); template <class T, class U> concept bool ExplicitlyConvertible() { return Same<T, U> || requires(T&& t) { static_cast<U>((T&&)(t)); }; } template <class T, class... Args> concept bool Constructible() { return ExplicitlyConvertible<Args..., T>() || requires (Args&&... args) { T{ (Args&&)(args)... }; }; } template <class T, class U> concept bool Constructible() { return ExplicitlyConvertible<U, T>() || requires (U&& u) { T{ (U&&)(u) }; }; } template <class T, class U> requires Constructible<T, U>() constexpr bool f() { return false; } template <class T, ExplicitlyConvertible<T> > constexpr bool f() { return true; } static_assert(f<int,int>(), ""); static_assert(f<int,long>(), ""); struct A { A(int); }; struct B { explicit B(int); }; static_assert(f<A, int>(), ""); static_assert(!f<B, int>(), ""); Yields: /cygdrive/c/Users/eric/Code/cmcstl2/test/core_concepts.cpp:32:25: error: invalid reference to function concept ‘template<class T, class U> constexpr bool Constructible()’ requires Constructible<T, U>() ^ /cygdrive/c/Users/eric/Code/cmcstl2/test/core_concepts.cpp:48:1: error: static assertion failed static_assert(!f<B, int>(), ""); ^ I can't make sense of the error. Is this just a bug?
I conjecture that Constructible<T, U>() is ambiguous, since both templates will specialize for it. I was thinking: template <class T> concept bool Constructible() { return requires { T{}; }; } template <class T, class U> concept bool Constructible() { return ExplicitlyConvertible<U, T>() || requires (U&& u) { T{ (U&&)(u) }; }; } template <class T, class First, class Second, class... Rest> concept bool Constructible() { return requires (First&& first, Second&& second, Rest&&... rest) { T{ (First&&)first, (Second&&)second, (Rest&&)(rest)... }; }; } which has no such ambiguities of specialization. (This is getting a little off-topic for this bug report - we should takes this offline.)
I would expect a partial ordering to prefer the two-parameter overload in that case. But yeah, it's a separate issue.
Exhaustively overloading Constructible to avoid the kind mismatch and the ambiguity runs into a different problem: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66841 I haven't filed an issue for the ambiguity/partial order problem. Should I, or is that by design? Either the kind mismatch problem needs to be fixed, or issue #66841. Right now I don't seem to have a way to express what I'm trying to express.
> I would expect a partial ordering to prefer the two-parameter overload in that > case. But yeah, it's a separate issue. The problem is that partial ordering doesn't apply to template parameters whose arguments can only be given explicitly. I got caught by this last year, and sent an email to core, and then (I think) Ville submitted a core issue or NB comment (I don't remember the details). Andrew
I think we should reconsider the rule against partial specialization of a variable concept, as that seems like the right way to handle this situation.
(In reply to Jason Merrill from comment #8) > I think we should reconsider the rule against partial specialization of a > variable concept, as that seems like the right way to handle this situation. Except that would still run into the DR 1430 issue: a requires-clause that uses a pack expansion would normalize using the primary template defined with a parameter pack, even if a later instantiation of that requires-clause would work better with a different partial specialization.
(In reply to Jason Merrill from comment #9) So it seems that applying the DR 1430 tentative resolution to concepts severely limits the usability of variadic concepts, and we should reconsider that, so that instead we delay normalization of template-ids with variadic arguments until instantiation time. The restriction on expansion arguments to non-expansion parameters initially applied to all variadic templates until N2555, which Eric was also involved with... I guess I'll revert my change for the moment.
Author: jason Date: Tue Jul 14 04:11:11 2015 New Revision: 225758 URL: https://gcc.gnu.org/viewcvs?rev=225758&root=gcc&view=rev Log: PR c++/66092 PR c++/66834 * gcc/cp/pt.c (coerce_template_parms): Revert earlier change. Removed: branches/c++-concepts/gcc/testsuite/g++.dg/concepts/dr1430.C Modified: branches/c++-concepts/ChangeLog.concepts branches/c++-concepts/gcc/cp/pt.c
> So it seems that applying the DR 1430 tentative resolution to concepts severely > limits the usability of variadic concepts, and we should reconsider that, so > that instead we delay normalization of template-ids with variadic arguments > until instantiation time. > > The restriction on expansion arguments to non-expansion parameters initially > applied to all variadic templates until N2555, which Eric was also involved > with... I don't think that's a good idea. It means the template-id would be characterized as an atomic constraint for purposes of partial ordering. You lose the ability to order on constraints within the concept, which means you're no better off than using a type trait for the definition. I would make the following observations: 1. Variadics require meteaprogramming and pattern matching 2. The constraint are not intended to be turing complete, so we can't reason about metaprograms 3. There may be useful logical extensions to the constraint language for working with variadics in principled ways 4. Some variadic constraints might be useful as core language constraints (intrinsics). Plus, I have a feeling that I'm going to to have to re-think the entire concept definition and requires-expression bit when we propose concepts for C++. There were too many NB comments to ignore. Andrew
(In reply to Andrew Sutton from comment #12) > I don't think that's a good idea. It means the template-id would be > characterized as an atomic constraint for purposes of partial > ordering. You lose the ability to order on constraints within the > concept, which means you're no better off than using a type trait for > the definition. True, I guess it's a trade-off between power and ease of use. Should I re-apply the change to coerce_template_parms?
Author: jason Date: Fri Jul 17 17:43:09 2015 New Revision: 225959 URL: https://gcc.gnu.org/viewcvs?rev=225959&root=gcc&view=rev Log: PR c++/66092 PR c++/66834 * gcc/cp/pt.c (coerce_template_parms): Re-apply earlier change. Added: branches/c++-concepts/gcc/testsuite/g++.dg/concepts/dr1430.C Modified: branches/c++-concepts/ChangeLog.concepts branches/c++-concepts/gcc/cp/pt.c
*** Bug 66841 has been marked as a duplicate of this bug. ***
Suspending.
*** Bug 79686 has been marked as a duplicate of this bug. ***