I'm using C++17. I made following code that is supposed to use SFINAE to test if lambda is compilable or not (lambda is always syntactically correct but may be uncompilable e.g. due to absence of some methods used in body):
#include <type_traits>
#include <sstream>
#include <iostream>
#include <tuple>
template <typename ... Ts>
struct Types {
using types = std::tuple<Ts...>;
template <size_t I>
using type = std::tuple_element_t<I, types>;
};
template <typename F, typename Enable = void, typename ... Ts>
struct Compilable : std::false_type {};
template <typename F, typename ... Ts>
struct Compilable<F,
std::void_t<decltype((*(F*)0)(Types<Ts...>{}))>, Ts...>
: std::true_type {};
template <typename ... Ts, typename F>
bool constexpr Comp(F const & f) {
return Compilable<F, void, Ts...>::value;
}
template <typename T>
void Test() {
std::cout << Comp<T>([](auto Ts){
typename decltype(Ts)::template type<0> * p = 0;
std::stringstream ss; ss << (*p); }) << std::endl;
}
struct X {};
int main() {
Test<int>();
Test<X>();
}
I hoped that uncompilable specialization will be silently excluded due to SFINAE, but instead it throws compilation error (for the second Test<X>()
case, first test compiles):
<source>:30:34: error: invalid operands to binary expression
('std::stringstream' (aka 'basic_stringstream<char>') and
'typename decltype(Ts)::type<0>' (aka 'X'))
std::stringstream ss; ss << (*p); }) << std::endl;
What am I doing wrong? Am I using SFINAE mechanism wrongly? What should be the right way to implement code above?