Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do C++20 concepts (requirement expression) using std::is_arithmetic_v fail to enforce type constraints?

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?

like image 671
undefined Avatar asked Sep 01 '25 04:09

undefined


1 Answers

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

like image 169
Erel Avatar answered Sep 02 '25 17:09

Erel