Re: Is this valid code?
Marian Ciobanu wrote:
On Mon, 10 Sep 2007 09:31:51 -0600, Nicola Musatti wrote:
[...]
As for the SFINAE I would make 2 statements:
1) SFINAE does care about what errors you get. On page 107 of "C++
Templates" by D. Vandevoorde & N. Josuttis you'll find this:
"The SFINAE principle protects only against attempts to create
invalid types but not against attempts to evaluate invalid
expressions.
Of course.
2) All the code that I've seen (and that I've wrote) that used
SFINAE involved a template function (global or member). Your "fn"
functions are not template functions. They are regular functions,
members of a template class.
As far as I know this only implies that their *declarations* are
instantiated whenever their class definition is instantiated, but as
declaring a function to take an incomplete type as argument is not an
error, this shouldn't cause any problem.
Here's a little piece of code that
fails to compile [...] because "f" are regular functions and so
SFINAE doesn't apply to them. It doesn't matter that they are
never called.
The mere existence of the second one causes an error
if T doesn't have a Q.
template <class T>
struct X
{
int f(...) { return 0; }
int f(typename T::Q) { return 1; }
};
The problem here is that if T doesn't have a Q the *declaration* of
the second f() overload is invalid and as this declaration is
instantiated whenever the corresponding class definition is, this is
always an error.
struct A { typedef int Q; };
struct B {};
int main()
{
X<A> xa;
X<B> xb;
}
So if SFINAE removed all overloads that would create errors, it
should have removed the second "f" in X<B> to make the code
compilable. But it didn't, because only template overloads are
removed, and they are removed if there's a missing type in their
signature, not if they have some other errors in their signatures
or their body.
You seem to be forgetting that SFINAE takes place only when the
construction of an overload candidate set requires some function
template to be instantiated. If such an instantiation would result in
an error the candidate is discarded, but the error is not reported. In
your case there's no call to f() so no overload candidate set is
built.
Let's go back to my example.
static no fn( ... );
static yes fn(C<T>);
Just declaring these should be no problem.
static C<T> const& make();
This returns a reference, so no problem here too.
static const bool value = sizeof( fn( make() ) ) == sizeof(yes);
Here I'm now less sure. I'm convinced that the second overload should
be removed by SFINAE, but does the ellipsis cause a C<T> const& to
C<T> conversion? If that was the case, this would be an error.
Cheers,
Nicola Musatti
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]