Edit, in order to avoid confusion:
decltype
does not accept two arguments. See answers.
The following two structs can be used to check for the existance of a member function on a type T
during compile-time:
// Non-templated helper struct:
struct _test_has_foo {
template<class T>
static auto test(T* p) -> decltype(p->foo(), std::true_type());
template<class>
static auto test(...) -> std::false_type;
};
// Templated actual struct:
template<class T>
struct has_foo : decltype(_test_has_foo::test<T>(0))
{};
I think the idea is to use SFINAE when checking for the existance of a member function, so in case p->foo()
isn't valid, only the ellipses version of test
, which returns the std::false_type
is defined. Otherwise the first method is defined for T*
and will return std::true_type
. The actual "switch" happens in the second class, which inherits from the type returned by test
. This seems clever and "lightweight" compared to different approaches with is_same
and stuff like that.
The decltype
with two arguments first looked surprising to me, as I thought it just gets the type of an expression. When I saw the code above, I thought it's something like "try to compile the expressions and always return the type of the second. Fail if the expressions fail to compile" (so hide this specialization; SFINAE).
But:
Then I thought I could use this method to write any "is valid expression" checker, as long as it depends on some type T
. Example:
...
template<class T>
static auto test(T* p) -> decltype(bar(*p), std::true_type());
...
http://ideone.com/dJkLPF
This, so I thought, will return a std::true_type
if and only if bar
is defined accepting a T
as the first parameter (or if T
is convertible, etc...), i.e.: if bar(*p)
would compile if it was written in some context where p
is defined of type T*
.
However, the modification above evaluates always to std::false_type
. Why is this? I don't want to fix it with some complicated different code. I just want to know why it doesn't work as I expected it to. Clearly, decltype
with two arguments works different than I thought. I couldn't find any documentation; it's only explained with one expression everywhere.