AMDG
Tobias Schwinger writes:
I don't think the comma operator
is a completely fool-proof way to detect void.
It is.
It could cause an
ambiguity if the other type also defines an overloaded comma operator.
No, because the operator is binary and one operand can have a reserved
type which is only internally used by the test code.
Ok. Let's make this concrete. Here is what I imagine:
struct tester1 {};
struct tester2 {};
typedef char no;
struct yes { no dummy[2]; };
template<class T>
tester2 operator,(T, tester1);
template<class T>
no test(T);
template<class T>
yes test(tester2);
template<bool is_void>
struct call_impl;
template<>
struct call_impl<true> {
template
R apply(F f, T t) {
f(t);
BOOST_ASSERT(!"Void function cannot return to call"
"when the return type is not void");
}
};
template<>
struct call_impl<false> {
template
R apply(F f, T t) {
return(f(t));
}
};
template
R call(F f, T t) {
return call_impl<
sizeof(test(f(t), tester1())) == sizeof(yes)
>::template apply<R>(f, t);
}
Suppose that we create a type:
struct X {};
template<class T>
T operator,(X, T);
X f(X);
And then try
call<X>(f, X())
The expression f(t), tester1() is ambiguous. It matches both
comma operators and neither operator is more specialized than
the other. How do you get around this? Remember that f(t)
only needs to be convertible to the result type so we can't
look for an exact match. Adding implicit conversions doesn't
work because the other comma operator can mirror such conversions.
In Christ,
Steven Watanabe