4

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?

3
  • There should be massive duplication of double-requires-related questions.. Commented May 31 at 9:05
  • 5
    Roughly speaking, "requires" only requires that whatever is inside that clause gets a clean compile; as such, your clause is pretty much a no-op. Commented May 31 at 9:17
  • Can it be understood figuratively that after I replace the template parameter T with the actual type, for the simple requirement, it checks whether the statement has any compilation syntax errors. eg. std::is_arithmetic_v<std::string>_v can evaluate to get result 'false' so it passes the first version of concept arithmetic Commented May 31 at 9:22

1 Answer 1

6

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.