Why does C++20's concept constraint not work as expected?

113 Views Asked by At
#include <concepts>
#include <string>
#include <type_traits>

template<typename T>
requires requires(T const& t) {
    !std::is_enum_v<T>;
    { std::to_string(t) } -> std::same_as<std::string>;
}
void Foo(T const&) {
}

template<typename T>
requires std::is_enum_v<T>
void Foo(T const&) {
}

enum Color {
    Red,
    Green,
    Blue,
};

int main() {
    Foo(Red); // error: Call to 'Foo' is ambiguous
}

Obviously, the two overloaded Foo are mutually exclusive; that is to say, if std::is_enum_v<T> is true, the former should not be selected. But clang-18 -std=c++20 gives an error.

Why does C++20's concept constraint not work as expected?

1

There are 1 best solutions below

5
0xbachmann On BEST ANSWER

The !std::is_enum_v<T> in the requires block is well formed and thus accepted. To check the value you need to write requires(!std::is_enum_v<T>). Both things can be combined as in the below example:

template<typename T>
requires(!std::is_enum_v<T>) && 
requires(T const& t) {
    { std::to_string(t) } -> std::same_as<std::string>;
}
void Foo(T const&) {
}

See Demo