I'm trying out templates and concepts in C++. I wrote the following code.
#include <iostream>
#include <string>
template <typename T>
concept Printable = requires(T a) {
{ to_string(a) } -> std::same_as<std::string>;
};
typedef struct myStruct {
std::string name;
} myStruct_t;
// Implement to_string for myStruct_t
std::string to_string(myStruct_t arg) {
return arg.name;
}
// Implement to_string for int
std::string to_string(int arg) {
return "it's an integer";
}
// a function that requires Printable
template <typename T>
requires Printable<T>
void show(T arg) {
std::cout << to_string(arg) << std::endl;
}
int main(){
myStruct_t a = {"hello"};
show(a); // passes compilation
show(5); // error: no matching function for call to ‘show(int)’
// note: the required expression ‘to_string(a)’ is invalid
return 0;
}
The compiler successfully recognizes that myStruct_t
satisfies Printable
concept but fails to match int
with Printable
concept. I wonder how I can inform the compiler that the int
is also Printable
.
I've searched the internet and found that the compiler finds the to_string
function needed for Printable
concept through argument-dependent lookup(ADL). Since int
is not subject to ADL, the compiler fails to recognize the function when trying to check int
in Printable
. I wonder if there's no way to make int
Printable
.
Using gcc and -fconcepts-diagnostics-depth=2
we see:
<source>:216:21: in requirements with 'T a' [with T = int]
<source>:217:16: note: the required expression 'to_string(a)' is invalid, because
217 | { to_string(a) } -> std::same_as<std::string>;
| ~~~~~~~~~^~~
<source>:217:16: error: 'to_string' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation
<source>:230:13: note: 'std::string to_string(int)' declared here, later in the translation unit
230 | std::string to_string(int arg) {
| ^~~~~~~~~
This means, that the concept is not satisfied for int
, because at the point of the concept definition the function to_string(int)
was not declared yet.
I wonder if there's no way to make int Printable
You can either move the implementation of to_string(int)
above the concept or add a forward declaration there.
// forward-declare to_string for int
std::string to_string(int arg);
template <typename T>
concept Printable = requires(T a) {
{ to_string(a) } -> std::same_as<std::string>;
};
// [...]
// Implement to_string for int
std::string to_string(int arg) {
return "it's an integer";
}