Search code examples
c++c++20c++-conceptsif-constexpr

How to properly use concepts?


Currently, I am learning C++ and decided just start with C++20. However, these codes are driving me crazy, since I don't think the result makes any sense.

The following code will have the sentence Valid array. printed. What I meant above is that this is not right. It shouldn't print the sentence at all, since the type I inserted in the parameter doesn't match the concept.

Tested on VS2022 Preview 3 and an online compiler with newest GCC and C++2A(GNU) arguments, generated the same results.

#include <array>
#include <cstdio>
#include <iostream>
#include <type_traits>

using namespace std;

template<typename A> concept ProperArray = requires(A array)
{
    {array.max_size() >= 2U};
    {std::is_arithmetic_v<typename A::value_type> == true};
};

int main()
{
    constexpr bool b = ProperArray<array<std::string, 1>>;
    if constexpr (b)
        cout << "Valid array." << endl;
        
    std::cout << "Hello, Wandbox!" << std::endl;
}

Solution

  • So, two things.

    1. You are using simple requirements (the extra {} make those compound requirements technically, but since you don't use any optional feature of those, it's equivalent to a simple requirement). Those mostly verify that an expression is syntactically valid. Its value is immaterial to them. What you want is nested requirements:

      template<typename A> concept ProperArray = requires(A array)
      {
          //requires array.max_size() >= 2U;
          requires std::is_arithmetic<typename A::value_type>::value;
      };
      

      These requirements (whose expression must be a constant expression), check the value indeed. Mind however, that the parameters can only be used in unevaluated contexts, so you'll need another way to query the type for it's size. That may change in some way or form in the future.

    2. if constexpr outside of a template is moot. It doesn't do the same discarding magic it does when its condition is value-dependent on a template parameter. You could have used a regular if to the same effect.