Search code examples
c++templatesstandardsc++20c++-concepts

Why does C++20 not support "void f(Concept const auto&)"?


#include <string>

template<typename T>
concept HasSize = requires(T obj)
{
    obj.size();    
};

void f1(HasSize auto arg) {} // ok
void f2(HasSize auto&& arg) {} // ok
void f3(HasSize decltype(auto) arg) {} // ok
void f4(HasSize auto& arg) {}  // ok
void f5(HasSize auto* arg) {}  // ok

void f6(HasSize const auto& arg) {} // error

int main()
{
    std::string str{};

    f1(std::string{});
    f2(std::string{});
    f3(std::string{});
    f4(str);
    f5(&str);
    f6(str);
}

Compiled with clang++ -std=c++20 -stdlib=libc++ z.cpp and the error messages are:

z.cpp:15:6: error: variable has incomplete type 'void'
void f6(HasSize const auto& arg) {} // error
     ^
z.cpp:15:9: error: too few template arguments for concept 'HasSize'
void f6(HasSize const auto& arg) {} // error
        ^
z.cpp:4:9: note: template is declared here
concept HasSize = requires(T obj)
        ^
z.cpp:15:33: error: expected ';' after top level declarator
void f6(HasSize const auto& arg) {} // error
                                ^
                                ;
3 errors generated.

Why does C++20 not support "void f(Concept const auto&)"?


Solution

  • You have the syntax wrong.

    type-constraints, such as the concept HasSize here, belong directly before the placeholder-type-specifier, i.e. before auto or decltype(auto):

    void f6(const HasSize auto& arg) {}
    

    See [dcl.spec.auto] of the C++20 draft.

    The cv-qualifiers, such as const, are separate from the placeholder-type-specifiers, see [decl.type]/1.


    As mentioned by @super in a question comment decltype(auto) is not allowed in a function parameter. So this seems to be a Clang bug to accept it, see [dcl.spec.auto]/2 which only allows the auto case for a placeholder-type-specifier in a function parameter.