I encountered unexpected behavior while implementing C++20 concepts based on an example from "Template Metaprogramming with C++: Learn everything about C++ templates and unlock the power of template metaprogramming" (by Marius Bancila, 2022).
The following are two versions of concept
definitions, which are expected to be equivalent:
Version 1:
template<typename T>
concept arithmetic = requires {
std::is_arithmetic_v<T>;
};
Version 2:
template<typename T>
concept arithmetic = std::is_arithmetic_v<T>;
However, using the first version:
#include <type_traits>
#include <string>
#include <iostream>
template<typename T>
concept arithmetic = requires {
std::is_arithmetic_v<T>;
};
template <typename T>
requires arithmetic<T>
T add(T const a, T const b) { return a + b; }
int main() {
add("a", "b");
}
Both Visual Studio 2022 and https://cppinsights.io/ with -std=c++20
give me a compile error:
'+': cannot add two pointers
But using the next version:
#include <type_traits>
#include <string>
#include <iostream>
template<typename T>
concept arithmetic = std::is_arithmetic_v<T>;
template <typename T>
requires arithmetic<T>
T add(T const a, T const b) { return a + b; }
int main() {
add("a", "b");
}
The same compilers with the same compile flags give me a different error:
'add': no matching overloaded function found
According to the C++ standard, a simple requirement in a requires
clause only checks if the expression is valid, not its boolean value.
Why does the requires
-based approach fail here? How can I align the concept
definition with the book's intended behavior?
The following are two versions of concept definitions, which are expected to be equivalent:
They are not.
The first version checks the expression std::is_arithmetic_v
is valid for type T
.
You want:
template<typename T>
concept arithmetic = requires {
requires std::is_arithmetic_v<T>;
// ^~~~~~~
};
Then, all three major compilers output similar error messages: https://godbolt.org/z/41conjGrj