SFINAE + sizeof = detect if expression compiles

2019-01-22 15:31发布

问题:

I just found out how to check if operator<< is provided for a type.

template<class T> T& lvalue_of_type();
template<class T> T  rvalue_of_type();

template<class T>
struct is_printable
{
    template<class U> static char test(char(*)[sizeof(
        lvalue_of_type<std::ostream>() << rvalue_of_type<U>()
    )]);
    template<class U> static long test(...);

    enum { value = 1 == sizeof test<T>(0) };
    typedef boost::integral_constant<bool, value> type;
};

Is this trick well-known, or have I just won the metaprogramming Nobel prize? ;)

EDIT: I made the code simpler to understand and easier to adapt with two global function template declarations lvalue_of_type and rvalue_of_type.

回答1:

It's a well known technique, I'm afraid :-)

The use of a function call in the sizeof operator instructs the compiler to perform argument deduction and function matching, at compile-time, of course. Also, with a template function, the compiler also instantiates a concrete function from a template. However, this expression does does not cause a function call to be generated. It's well described in SFINAE Sono Buoni PDF.

Check other C++ SFINAE examples.



回答2:

It is just a combination of two well-known tricks. SFINAE says 'substitution failure is not an error' - that's exactly what you did. Using sizeof to let the compiler substitute template arguments into an expression without actually executing it is also common.

Sorry :-)