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

C++ 20 Concepts: Require operator overloading


I am trying to understand how to declare a concept that requires a particular operator is overloaded for a given type. Lets say I have the following function that takes a vector of an arbitrary type and prints it to std::cout:

template<typename printable>
void print_vector(const std::vector<printable>& vec) 
{
    std::cout << '{';
    for (const printable &item : vec) {
        std::cout << item << ',';
    }
    std::cout << '}';
}

This code will work just fine if the type printable has an overloaded << operator, but if it doesn't, then it fails with a very unhelpful compiler error. I feel like I should be able to somehow declare a concept that requires a type has a valid << operator defined, and use that concept in the function declaration, so that I can get a more useful compiler error, but I haven't been able to figure out how to do it.


Solution

  • template <class T>
    concept Printable = requires(std::ostream& os, T a)
    {
        os << a;
    };
    
    
    template<Printable T>
    void print_vector(const std::vector<T>& vec) {
      std::cout << '{';
      for (const auto &item : vec) {
        std::cout << item << ',';
      }
      std::cout << '}';
    }
    

    If you wish you could also make it more generic to operate on basic_ostream.


    Here is the clang error message:

    <source>:30:5: error: no matching function for call to 'print_vector'
        print_vector(x);
        ^~~~~~~~~~~~
    <source>:19:6: note: candidate template ignored: constraints not satisfied [with T = X]
    void print_vector(std::vector<T> vec) {
         ^
    <source>:18:10: note: because 'X' does not satisfy 'Printable'
    template<Printable T>
             ^
    <source>:10:9: note: because 'os << a' would be invalid: invalid operands to binary expression ('std::ostream' (aka 'basic_ostream<char>') and 'X')
        os << a;
           ^
    

    and gcc:

    <source>: In function 'auto test()':
    <source>:30:19: error: use of function 'void print_vector(std::vector<T>) [with T = X]' with unsatisfied constraints
       30 |     print_vector(x);
          |                   ^
    <source>:19:6: note: declared here
       19 | void print_vector(std::vector<T> vec) {
          |      ^~~~~~~~~~~~
    <source>:19:6: note: constraints not satisfied
    <source>: In instantiation of 'void print_vector(std::vector<T>) [with T = X]':
    <source>:30:19:   required from here  
    <source>:8:9:   required for the satisfaction of 'Printable<T>' [with T = X]
    <source>:8:21:   in requirements with 'std::ostream& os', 'T a' [with T = X]    
    <source>:10:9: note: the required expression '(os << a)' is invalid    
       10 |     os << a;
          |     ~~~^~~~
    cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail