Bug 96331 - Class template argument deduction (CTAD) with Concepts
Summary: Class template argument deduction (CTAD) with Concepts
Status: RESOLVED DUPLICATE of bug 93083
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2020-07-27 11:55 UTC by Nicole
Modified: 2022-03-09 17:10 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-10-02 00:00:00


Attachments
Pre-processed source file (133.49 KB, text/plain)
2020-07-27 11:55 UTC, Nicole
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Nicole 2020-07-27 11:55:51 UTC
Created attachment 48932 [details]
Pre-processed source file

I have the following program shown at the bottom of this posting.

The error messages generated are shown after the program. It seems that reason the compilation fails is that there is no match for fixed_string constructor: fixed_string(fixed_string<...auto...>). I can find nothing about what "<...auto...>" might mean, so cannot create a suitable function. Is the reported lack of such a constructor the result of missing support for CTAD with Concepts, or have I missed something else? I am not a "language lawyer".

The fixed_string class is lifted almost verbatim from a recent report of the C++ committee explaining why support of string literals for templates will not be supported (http://open-std.org/JTC1/SC22/WG21/docs/papers/2019/p1837r0.html).

---------------------------

The compiler used is the latest, stock gcc from Arch Linux:

~$ gcc --version
gcc (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

-----------------------------

System used is stock GNU/Linux from Arch:

~$ uname -a
Linux workbench 5.7.9-arch1-1 #1 SMP PREEMPT Thu, 16 Jul 2020 19:34:49 +0000 x86_64 GNU/Linux

-----------------------------

The command line generating this situation:

g++ -std=gnu++20 -O0 -g3 -pedantic -pedantic-errors -Wall -Wextra -Werror -c -pthread -fmessage-length=0 -fPIC -o test-concepts.o test-concepts.cpp

============================= Program ================================

#include <string>
#include <cstring>

template<std::size_t N>
struct fixed_string {
    static const constexpr std::size_t size__ = N;

    constexpr fixed_string(char const* s) :
        buf("") {
        for (std::size_t i = 0; i <= N; ++i)
            buf[i] = s[i];
    }
    constexpr operator char const*() const {
        return buf;
    }
    template<std::size_t M>
    constexpr bool compare(const fixed_string<M>& other) const {
        return N == M && ::strncmp(buf, other.buf, N) == 0;
    }

    char buf[N + 1];
};

template<std::size_t N>
fixed_string(char const (&)[N]) -> fixed_string<N - 1>;

template<fixed_string TARGET_NAME, typename TYPE>
concept NameMatcher = (TARGET_NAME.compare(TYPE::name__));

////////////////////////////////////////////

template<fixed_string NAME, typename TYPE>
class Member {
public:
    static const constexpr fixed_string name__ { NAME };

public:
    Member() :
        member_ { } {

    }

    template<fixed_string TARGET_NAME>
    const TYPE& get()
        const requires NameMatcher<TARGET_NAME, TYPE> {
        return member_;
    }

protected:
    TYPE member_;
};

////////////////////////////////////////////

template<typename ... MEMBERS>
class Container: public MEMBERS... {
};

////////////////////////////////////////////

int main(int, char*[]) {
    Container<Member<"fred", int>, Member<"bert", float>,
          Member<"alfie", bool>> container;
    return container.get<"fred">();
}

=============================== Messages ===============================

test-concepts.cpp:47:35: error: class template argument deduction failed:
   47 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE> {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-concepts.cpp:47:35: error: no matching function for call to ‘fixed_string(fixed_string<...auto...>)’
test-concepts.cpp:8:12: note: candidate: ‘template<long unsigned int N> fixed_string(const char*)-> fixed_string<N>’
    8 |  constexpr fixed_string(char const* s) :
      |            ^~~~~~~~~~~~
test-concepts.cpp:8:12: note:   template argument deduction/substitution failed:
test-concepts.cpp:47:35: note:   couldn’t deduce template parameter ‘N’
   47 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE> {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-concepts.cpp:5:8: note: candidate: ‘template<long unsigned int N> fixed_string(fixed_string<N>)-> fixed_string<N>’
    5 | struct fixed_string {
      |        ^~~~~~~~~~~~
test-concepts.cpp:5:8: note:   template argument deduction/substitution failed:
test-concepts.cpp:47:35: note:   mismatched types ‘fixed_string<N>’ and ‘fixed_string<...auto...>’
   47 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE> {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-concepts.cpp:28:1: note: candidate: ‘template<long unsigned int N> fixed_string(const char (&)[N])-> fixed_string<(N - 1)>’
   28 | fixed_string(char const (&)[N]) -> fixed_string<N - 1>;
      | ^~~~~~~~~~~~
test-concepts.cpp:28:1: note:   template argument deduction/substitution failed:
test-concepts.cpp:47:35: note:   mismatched types ‘const char [N]’ and ‘fixed_string<...auto...>’
   47 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE> {
      |                                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-concepts.cpp: In function ‘int main(int, char**)’:
test-concepts.cpp:65:19: error: request for member ‘get’ is ambiguous
   65 |  return container.get<"fred">();
      |                   ^~~
test-concepts.cpp:47:14: note: candidates are: ‘template<fixed_string<...auto...> TARGET_NAME> const TYPE& Member<NAME, TYPE>::get() const requires  <erroneous-expression> [with fixed_string<...auto...> TARGET_NAME = TARGET_NAME; fixed_string<...auto...> NAME = fixed_string<5>{"alfie"}; TYPE = bool]’
   47 |  const TYPE& get() const requires NameMatches<TARGET_NAME, TYPE> {
      |              ^~~
test-concepts.cpp:47:14: note: ‘template<fixed_string<...auto...> TARGET_NAME> const TYPE& Member<NAME, TYPE>::get() const requires  <erroneous-expression> [with fixed_string<...auto...> TARGET_NAME = TARGET_NAME; fixed_string<...auto...> NAME = fixed_string<4>{"bert"}; TYPE = float]’
test-concepts.cpp:47:14: note: ‘template<fixed_string<...auto...> TARGET_NAME> const TYPE& Member<NAME, TYPE>::get() const requires  <erroneous-expression> [with fixed_string<...auto...> TARGET_NAME = TARGET_NAME; fixed_string<...auto...> NAME = fixed_string<4>{"fred"}; TYPE = int]’
test-concepts.cpp:65:31: error: expected primary-expression before ‘)’ token
   65 |  return container.get<"fred">();
      |                               ^
Comment 1 Jonathan Wakely 2020-07-27 12:11:44 UTC
(In reply to Nicole from comment #0)
> template<fixed_string NAME, typename TYPE>

This is not valid. fixed_string is a class template, not a type and not a concept. So you can't use it as a template parameter.

I don't think this is a bug.
Comment 2 TC 2020-07-30 04:37:27 UTC
(In reply to Jonathan Wakely from comment #1)
> (In reply to Nicole from comment #0)
> > template<fixed_string NAME, typename TYPE>
> 
> This is not valid. fixed_string is a class template, not a type and not a
> concept. So you can't use it as a template parameter.
> 
> I don't think this is a bug.

It is a placeholder for a deduced class type, which is allowed by [temp.param]/6.3.

The example can be reduced drastically:

template<int N = 0>
struct S { };

template<S>
concept C = true;

static_assert(C<S<0>{}>); // OK

template<S Value>
void f() requires C<Value> { // error
}

<source>:11:19: error: class template argument deduction failed:

   11 | void f() requires C<Value> {

      |                   ^~~~~~~~

<source>:11:19: error: no matching function for call to 'S(S<...auto...>)'

<source>:2:8: note: candidate: 'template<int N> S()-> S<N>'

    2 | struct S {

      |        ^

<source>:2:8: note:   template argument deduction/substitution failed:

<source>:11:19: note:   candidate expects 0 arguments, 1 provided

   11 | void f() requires C<Value> {

      |                   ^~~~~~~~

<source>:2:8: note: candidate: 'template<int N> S(S<N>)-> S<N>'

    2 | struct S {

      |        ^

<source>:2:8: note:   template argument deduction/substitution failed:

<source>:11:19: note:   mismatched types 'S<N>' and 'S<...auto...>'

   11 | void f() requires C<Value> {

      |                   ^~~~~~~~

Compiler returned: 1
Comment 3 Jonathan Wakely 2020-10-02 23:01:52 UTC
Reopening then, thanks, Tim.
Comment 4 Pilar Latiesa 2020-10-28 13:53:40 UTC
Another testcase, taken from https://stackoverflow.com/questions/64567607/why-is-there-an-error-no-matching-function-for-call-to-aa-auto

template <typename T>
struct A {};

template <A>
struct B {};

template <typename>
struct is_B {};

template <A x>
struct is_B<B<x>> {}; // error

template <A x>
using B_t = B<x>; // error
Comment 5 Patrick Palka 2022-03-09 17:10:46 UTC
This appears to be a dup of PR93083 which is fixed for GCC >= 10.3.

*** This bug has been marked as a duplicate of bug 93083 ***