
Doug Gregor wrote:
Hi Tobias,
On Dec 27, 2006, at 7:51 AM, Tobias Schwinger wrote:
Hi Doug and Boost community,
I noticed that the Boost implementation of result_of uses inheritance to forward the type member of a nested result metafunction, so that result_of<...>::type can result in a substitution failure (and not an error when used in an appropriate context) if the nested result class template does not have a type member.
It's surely a nice feature (also because it usually stops trace diagnostics at a reasonable point in case of an error). Should the standard text perhaps encforce that kind of implementation - e.g:
[tr.func.ret.ret] 2 5 (b)
If N>0, result_of<F(T1, T2, ... TN)> inherits from F::result<F(T1, T2, ... TN)>
? Comments?
Hmmm, that was an accidental feature... so we could construct a case where one could exploit this functionality:
struct X { template<typename F> struct result {}; template<> struct result<X(int&)> { typedef int& type; }
int& operator()(int&);
operator bool() const; };
template<typename F> typename boost::result_of<F(int&)>::type foo(F f); bool foo(bool);
X x; foo(x); // works if we use inheritance for X::result<X(int&)>, fails otherwise
It doesn't really take that esoteric of a case to be useful, though. Let's consider a variadic function wrapper and a call that doesn't fit the arity of the wrapped object: Now, with "SFIANE propagation" we get "no match for call to <wrapper>..." reported in client code - without "SFINAE propagation" we get "no match for call to <wrapped>...", reported in the gory details of the wrapper and (possibly lots of) trace diagnostics burying it.
Now, in C++0x, the metaprogramming-based implementation and specification of result_of is going to disappear in favor of decltype.
We can remove that nested result class template, then...
With a decltype-based implementation, the code above would be ill-formed, so I think the right answer is "do the same thing that the decltype implementation would do."
... but I guess we might be able to use that very language extension to detect whether a function object has a call operator that suits given argument types. Further, a client may still define a specialization for std::result_of to control whatever is in there. Not trying to convince you - just thinking aloud... Thanks for your reply. Regards, Tobias