consider this example:
#include <iostream>
#include <utility>
template<typename T>
concept Printable = requires(const T a) {
a.print();
};
template<typename T>
constexpr auto is_printable() {
return Printable<T>;
}
template<class T, std::enable_if_t<is_printable<T>()>* = nullptr>
constexpr void do_print(T data) {
data.print();
}
struct foo {
void print() const {
std::cout << "Hello World\n";
}
};
int main() {
foo f;
do_print(f);
}
trying to compile this on MSVC (Version 16.9.4, /std:c++latest) will produce these errors:
Error C2783 'void do_print(T)': could not deduce template argument for '__formal'
Error C2672 'do_print': no matching overloaded function found
It failed to satisfy the std::enable_if_t
.
I discovered the error comes from the auto
in constexpr auto is_printable() { ... }
, and replacing the the auto
with bool
will correctly compile.
template<typename T>
constexpr bool is_printable() {
return Printable<T>;
}
I find this very bizarre, the concept Printable<T>
is evaluated at compile time and should produce a constexpr bool
. Why does auto
fail suddenly?
This is an MSVC bug. Your code is correct. I highly recommend reporting the issue. Your code works correctly on GCC and Clang.
In the meantime, I would simply drop the SFINAE. It is not really needed when you got concepts that replaces enable ifs:
#include <iostream>
#include <utility>
template<typename T>
concept Printable = requires(const T a) {
a.print();
};
constexpr void do_print(Printable auto data) {
data.print();
}
struct foo {
void print() const {
std::cout << "Hello World\n";
}
};
int main() {
foo f;
do_print(f);
}
You can also use requires
or even replace typename
with your concept:
template<typename T> requires Printable<T>
constexpr void do_print(T data) {
data.print();
}
template<Printable T>
constexpr void do_print(T data) {
data.print();
}