failed to recognize concept type as bool in SFINAE

Viewed 103

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?

1 Answers

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();
}
Related