Muhammad
Muhammad

Reputation: 1655

concept constraints don't apply

I've the following code

#include <cstdint>
#include <concepts>

template <class T>
concept has_id = requires(T) {
    T::Id;
    std::same_as<uint8_t[16], decltype(T::Id)>;
};

The has_id concepts ensure that a type has the member Id with type uint8_t[16].

However, when writing the following example it works even though the Id has type uint8_t[17] which is invalid.

#include <cstdint>
#include <iostream>

class Sample
{
public:
    static constexpr uint8_t Id[17] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,10,11};
};

template<has_id T>
void print_id()
{
    std::cout.setf(std::ios_base::hex);

    std::cout << "{" << (int)T::Id[0];

    for(auto i=1; i < sizeof(T::Id); ++i)
        std::cout << ", " << (int)T::Id[i];

    std::cout << "}";
}

int main()
{
    print_id<Sample>();

    return 0;
}

I've tried it on Visual C++ 2022 17.3 and Clang 14 and they give the same result, any idea why?

Upvotes: 1

Views: 378

Answers (3)

Useless
Useless

Reputation: 67733

template <class T>
concept has_id = requires(T) {
    T::Id;
    std::same_as<uint8_t[16], decltype(T::Id)>;
};

Confirms that the expression T::Id compiles, and that the expression std::same_as<....> compiles. It doesn't check whether the latter is true or false.

You can just write

template <class T>
concept has_id = requires(T) {
    T::Id;
    requires std::same_as<uint8_t[16], decltype(T::Id)>;
};

to change the constraint from must compile to must be true.


Note GCC 12 helpfully emits the following warning with your original code:

<source>:7:2: warning: testing if a concept-id is a valid expression;
  add 'requires' to check satisfaction [-Wmissing-requires]

Upvotes: 3

Marek R
Marek R

Reputation: 37697

Here is my version which is more simple then other answers:

template <class T>
concept has_id = std::same_as<const uint8_t[16], decltype(T::Id)>;

Note also extra const you (and others) have missed in expression.

Live demo

Upvotes: 3

Nathan Pierson
Nathan Pierson

Reputation: 5565

Right now, your requirement just checks that std::same_as<uint8_t[16], decltype(T::Id)>; compiles. You want to use nested requirements to require that the value of std::same_as<...> is actually true. A fixed requirement would look like:

#include <cstdint>
#include <concepts>

template <class T>
concept has_id = requires(T) {
    T::Id;
    requires std::same_as<uint8_t[16], decltype(T::Id)>;
};

Upvotes: 2

Related Questions