Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this valid code?

14 views
Skip to first unread message

Nicola Musatti

unread,
Sep 6, 2007, 1:02:18 PM9/6/07
to
Hallo,
The following program is supposed to use SFINAE to identify whether a
specific template specialization is defined:

#include <iostream>
#include <ostream>

class A {};
class B {};

template <typename T> class X;

template <> class X<A> {};

template <template <typename> class C, typename T> class is_defined {
typedef char no;
typedef char (&yes)[2];

static no fn( ... );
static yes fn(C<T>);

static C<T> const& make();

public:
static const bool value = sizeof( fn( make() ) ) == sizeof(yes);
};

int main() {
std::cout << is_defined<X, A>::value << '\n';
std::cout << is_defined<X, B>::value << '\n';
}

Is this valid? Am I invoking undefined behaviour? I'm asking because
just about every compiler I have access to treats it differently.
Comeau 4.3.8 Beta complains that the return value of make() cannot be
converted to X<B>, because it is incomplete;
Microsoft VC++ 2005 outputs
1
0
as I expected;
g++ 4.2.1 outputs
1
1
to my surprise;
g++ 3.4.5 and CodeGear (Borland) C++Builder 2007 U2 fail to compile
it. Who is right?

Thank you,
Nicola Musatti


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Gianni Mariani

unread,
Sep 7, 2007, 10:45:40 AM9/7/07
to
Nicola Musatti wrote:

>
> Is this valid?

I don't think it is valid. However I think the code below is valid but
it does not work on any of the compilers I tried. I must be missing
something.

#include <iostream>
#include <ostream>

class A {};
class B {};

template <typename T> class X;

template <> class X<A> { };

template <template <typename> class C, typename T> class is_defined {
typedef char no;
typedef char (&yes)[2];

struct Az {};
struct Bz : Az {};
static Bz & bfn();

static C<T>& make();

template <int V>
struct H;

template <typename Z>
static no fn( Z &, Az & );

template <typename Z>
static yes fn( Z &, Bz &, H<sizeof(Z)> * = 0 );

public:
static const bool value = sizeof( fn( make(), bfn() ) ) ==
sizeof(yes);
};

int main() {
std::cout << is_defined<X, A>::value << '\n';
std::cout << is_defined<X, B>::value << '\n';
}

> ... Am I invoking undefined behaviour?

Undefined behaviour is usually constrained to code that compiles. This
does not compile on any of the compilers I tried.

Marian Ciobanu

unread,
Sep 7, 2007, 7:03:17 PM9/7/07
to
Hi,

> Hallo,
> The following program is supposed to use SFINAE to identify whether a
> specific template specialization is defined:

I think the code is invalid. I'm surprised that GCC 4.2.1 compiles this,
because GCC 4.1.0 gives, and I believe rightly so, this message:
"invalid use of undefined type 'struct X<B1>'".

As far as I know, once you have "template <typename T> class X;",
any attempt to use X<Something> should give an error if X<Something>
isn't defined at the point of usage. SFINEA is about classes that are
defined but don't have some members. I don't think you can do
something with SFINEA for classes that are not defined (but I'll have
to think more about this).

So if it's acceptable to you, my suggestion would be to include some
"dummy", default implementation of X, with a typedef that's not going
to be used in any class.

It's been a while since the last time I did this kind of things, but
here's what I came up with in a few minutes:

#include <iostream>

class A {};
class B {};

template <typename T> struct X { typedef int DefaultImpl; };

template <template <typename> class C, typename T> class is_defined {

typedef char defined_ret;
typedef char (&default_ret)[2];

template<typename U> static defined_ret fn( ... );
template<typename U> static default_ret
fn(C<U>, typename C<U>::DefaultImpl = 0);

static C<T> const& make();

public:
static const bool value = sizeof( fn<T>( make() ) ) ==
sizeof(defined_ret);
};

template <> class X<A> {};

int main() {
std::cout << is_defined<X, A>::value << '\n';
std::cout << is_defined<X, B>::value << '\n';
}

I think it's possible to make this simpler, but I'd have to think
more about it, as my SFINAE is a bit rusty.

If I can come up with a version that doesn't use the "dummy"
implementation, I'll post it later (provided somebody else doesn't
do it first).


> to my surprise;
> g++ 3.4.5 and CodeGear (Borland) C++Builder 2007 U2 fail to compile
> it. Who is right?

GCC 3.4 is pretty old, so I wouldn't rely much on what it does.
As for Borland, I don't know about the 2007 version, but previous
versions had serious standard compliance issues.

Ciobi

Marian Ciobanu

unread,
Sep 8, 2007, 5:47:57 AM9/8/07
to
On Fri, 07 Sep 2007 17:03:17 -0600, Marian Ciobanu wrote:

> I think it's possible to make this simpler, but I'd have to think
> more about it, as my SFINAE is a bit rusty.

OK, I guess this is quite simple (but it still requires the "default"
implementation). I reordered the lines to emphasize that what matters
is definition at the point of usage.

#include <iostream>

template <template <typename> class C, typename T> class is_defined {

typedef char (&no)[2];

template<typename U> static char fn( ... );
template<typename U> static no fn(typename C<U>::DefaultImpl);

public:
static const bool value = sizeof( fn<T>(0) ) == sizeof( char );
};

template <typename T> struct X { typedef int DefaultImpl; };

class A {};
class B {};

template <> class X<A> {};

int main() {
std::cout << is_defined<X, A>::value << '\n';
std::cout << is_defined<X, B>::value << '\n';
}

Greg Herlihy

unread,
Sep 8, 2007, 5:47:56 AM9/8/07
to
On 9/6/07 10:02 AM, in article
1189084995.5...@k79g2000hse.googlegroups.com, "Nicola Musatti"
<nicola....@gmail.com> wrote:

> The following program is supposed to use SFINAE to identify whether a
> specific template specialization is defined:

In other words, the program is attempting to test whether a particular
template specialization is a complete type - at the point in the translation
unit where the test is applied.

> #include <iostream>


>
> class A {};
> class B {};
>
> template <typename T> class X;
>
> template <> class X<A> {};
>
> template <template <typename> class C, typename T> class is_defined {
> typedef char no;
> typedef char (&yes)[2];
>
> static no fn( ... );
> static yes fn(C<T>);
>
> static C<T> const& make();
>
> public:
> static const bool value = sizeof( fn( make() ) ) == sizeof(yes);
> };
>
> int main() {
> std::cout << is_defined<X, A>::value << '\n';
> std::cout << is_defined<X, B>::value << '\n';
> }
>
> Is this valid? Am I invoking undefined behaviour? I'm asking because
> just about every compiler I have access to treats it differently.
> Comeau 4.3.8 Beta complains that the return value of make() cannot be
> converted to X<B>, because it is incomplete;

The program is valid - it manages to avoid instantiating X<B> (which would
be a compile-time error) but only because the sizeof() expression does not
evaluate its argument. But otherwise the program does not accomplish
anything useful - nor could it ever be made to work as intended. Logically,
it is not possible to write a type trait class (like "is_defined" above) to
test a type for "completeness" - because the completeness of a type is not
an inherent property of that type - nor is it even likely to be a constant.
After all, a type may be incomplete at one point in a source file and be
completed later on in that same source file.

So even if is_defined worked, the fact that the static bool constant,
is_defined<>::value, can be initialized to both "true" and "false"- would
run afoul of C++'s One Definition Rule - as well as other requirements in
the Standard that do not permit the completeness of a type to affect the
semantics of the program.

Moreover, there is nothing useful that a program could do with a working
"is_defined" test in the first place. There are only two possibilities to
consider: either a program uses a particular type only in ways that do not
require that type to be complete (so whether the type is actually complete
or not is utterly irrelevant to the program's behavior); or, the program
uses a particular type in a way that requires a complete type - and in which
case the programmer (to prevent a compile-time error) has no choice but to
make sure that the type in question is complete.

Greg

Nicola Musatti

unread,
Sep 10, 2007, 11:31:51 AM9/10/07
to
On Sep 8, 1:03 am, Marian Ciobanu <ci...@inbox.com> wrote:
> Hi,
>
> > Hallo,
> > The following program is supposed to use SFINAE to identify whether a
> > specific template specialization is defined:
>
> I think the code is invalid. I'm surprised that GCC 4.2.1 compiles this,
> because GCC 4.1.0 gives, and I believe rightly so, this message:
> "invalid use of undefined type 'struct X<B1>'".
>
> As far as I know, once you have "template <typename T> class X;",
> any attempt to use X<Something> should give an error if X<Something>
> isn't defined at the point of usage. SFINEA is about classes that are
> defined but don't have some members. I don't think you can do
> something with SFINEA for classes that are not defined (but I'll have
> to think more about this).

First of all, there are acceptable uses for incomplete classes, like
declaring pointer or reference values to them, so your first statement
above is not correct. Second, SFINAE is about removing from an
overload set any specialization whose instantiation would cause an
error, regardless what the error is. What makes it difficult to use is
the fact that the error must take place in the instantiation of the
candidate specialization, not in any instantiation that is required by
it.

Thus I believe that simply declaring a member function of a template
that takes an incomplete class as argument not to be a problem.

> So if it's acceptable to you, my suggestion would be to include some
> "dummy", default implementation of X, with a typedef that's not going
> to be used in any class.

This is not acceptable because I cannot modify the one class for which
"is_defined" is needed.

Thanks all the same.

Cheers,
Nicola Musatti

Hendrik Schober

unread,
Sep 10, 2007, 11:31:41 AM9/10/07
to
Greg Herlihy <gre...@pacbell.net> wrote:
> On 9/6/07 10:02 AM, in article
> 1189084995.5...@k79g2000hse.googlegroups.com, "Nicola Musatti"
> <nicola....@gmail.com> wrote:
>
> > The following program is supposed to use SFINAE to identify whether a
> > specific template specialization is defined:


In this I recognize a problem I recently asked about in
comp.lang.c++ (news:46dbfa6b$0$90262$1472...@news.sunsite.dk
starts the thread) where Barry Ding came up with a
might-be solution that looks like what Nicola posted)
and in borland.public.cppbuilder.language.c++ (see

http://groups.google.de/group/borland.public.cppbuilder.language.cpp/msg/151bb93621bcab60
for the start of that thread) where Sergiy Kanilo came
up with the same idea.

> In other words, the program is attempting to test whether a particular
> template specialization is a complete type - at the point in the translation
> unit where the test is applied.

Yep. That was the original problem the code attempted to
be a solution for. :)

> [code snipped]
> The program is valid [...]

If so, then it uncovers a bug in Comeau (which it most
likely inherits from its EDG front end) and several
recent GCC versions.

> So even if is_defined worked, the fact that the static bool constant,
> is_defined<>::value, can be initialized to both "true" and "false"- would
> run afoul of C++'s One Definition Rule - as well as other requirements in
> the Standard that do not permit the completeness of a type to affect the
> semantics of the program.

I see. Chris Uzdavinis already said something similar.
(To this, Sergiy suggested using an unnamed namespace,
BTW.) However, in the cases I would be interested in
(see below), this wouldn't matter, as the meta function
would only ever be applied in the same context (i.e.,
the template always either is a complete type or not).

> Moreover, there is nothing useful that a program could do with a working
> "is_defined" test in the first place.

This depends upon your definition of "usefulness". :)

> There are only two possibilities to
> consider: either a program uses a particular type only in ways that do not
> require that type to be complete (so whether the type is actually complete
> or not is utterly irrelevant to the program's behavior); or, the program
> uses a particular type in a way that requires a complete type - and in which
> case the programmer (to prevent a compile-time error) has no choice but to
> make sure that the type in question is complete.

In b.p.c.l.c++ I gave example where I'd consider this a
useful meta function [the following slightly edited to
fix typos and to somewhat condense it]:
"The standard requires a std lib implementation to
provide (in namespace 'std'):
template< typename T > struct char_traits;
template<> struct char_traits<char> { /* ... */ };
template<> struct char_traits<wchar_t> { /* ... */ };
Many std lib implementations provide this and no more.
Some (e.g., Dinkumware) also provide an implementation
for the primary template.
Now, if you need 'std::char_traits<unsigned char>',
according to the standard you need to write your own.
This isn't hard, but given what I do and what the guys
at DW do for a living, it's likely their version is
better than mine. So if I'm on a platform where there
is an implementation for traits for 'unsigned char', I
want to use this. If not, I want to use mine. This is
a decision that needs to be done at compile-time, as I
need to define types with either of the traits.
Of course, I could do this with a lot of '#if's. But
given that we herd a whole bunch of compilers and std
lib implementations (and versions and combinations
thereof), I'd rather not do this. (It's just another
thing you have to fiddle with when you port to a new
platform/compiler/std lib/version.)"
Incidently, in the same message I re-phrased the original
question as:
"Given that I know what's supposed in such a template
(which is true for 'std::char_traits'), isn't there a
way to determine (again, at compile-time) whether a
template has a specific member that yields no if the
template isn't defined?"
ISTR having heard about some 'has_member<>' meta fucntion.

> Greg

Schobi

--
Spam...@gmx.de is never read
I'm HSchober at gmx dot de
"A patched buffer overflow doesn't mean that there's one less way attackers
can get into your system; it means that your design process was so lousy
that it permitted buffer overflows, and there are probably thousands more
lurking in your code."
Bruce Schneier

Nicola Musatti

unread,
Sep 10, 2007, 11:32:00 AM9/10/07
to
On Sep 8, 11:47 am, Greg Herlihy <gre...@pacbell.net> wrote:
[...]

> The program is valid - it manages to avoid instantiating X<B> (which would
> be a compile-time error) but only because the sizeof() expression does not
> evaluate its argument. But otherwise the program does not accomplish
> anything useful - nor could it ever be made to work as intended. Logically,
> it is not possible to write a type trait class (like "is_defined" above) to
> test a type for "completeness" - because the completeness of a type is not
> an inherent property of that type - nor is it even likely to be a constant.
> After all, a type may be incomplete at one point in a source file and be
> completed later on in that same source file.

[...]


> Moreover, there is nothing useful that a program could do with a working
> "is_defined" test in the first place. There are only two possibilities to
> consider: either a program uses a particular type only in ways that do not
> require that type to be complete (so whether the type is actually complete
> or not is utterly irrelevant to the program's behavior); or, the program
> uses a particular type in a way that requires a complete type - and in which
> case the programmer (to prevent a compile-time error) has no choice but to
> make sure that the type in question is complete.

Actually my program is an attempt to solve a problem pointed out by a
friend in a different newsgroup, namely the lack of an is_specialized
static data member in std::char_traits.

As not all available standard library implementations provide
specializations for all standard character variants he wrote his own
specializations, but would rather use the original ones when
available.

Cheers,
Nicola Musatti

Marian Ciobanu

unread,
Sep 11, 2007, 10:55:59 AM9/11/07
to
On Mon, 10 Sep 2007 09:31:51 -0600, Nicola Musatti wrote:

> First of all, there are acceptable uses for incomplete classes, like
> declaring pointer or reference values to them, so your first statement
> above is not correct. Second, SFINAE is about removing from an
> overload set any specialization whose instantiation would cause an
> error, regardless what the error is.

I guess my wording wasn't right. Of course pointers and references
to an undefined class can be used. I use them all the time. I was
talking about classes, not pointers to classes. You can use "C<T>*"
all you want. The troubles start the moment you use just "C<T>" and
it's not defined but the compiler wants to instantiate it. And the
question here is whether the compiler should instantiate X<B> or
not. I believe it should (and later remove it at link time, because
it's not actually used), but a "language lawyer" is better prepared
to answer this.

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. The following example is therefore invalid C++:

template<int I> void f(int (&)[24/(4-I)]);
template<int I> void f(int (&)[24/(4+I)]);

int main()
{
&f<4>; // ERROR: division by zero (SFINAE doesn't apply)
}"

(GCC 4.1.0 seems seriously broken when dealing with this example.
Hopefully that's fixed in 4.2; I'm quite sure that the example
is correct.)


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. Here's a little piece of code that
fails to compile on GCC 4.1.0 and on MSVC 2005 SP1 (and I guess
on other systems too), 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; }
};

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.

Regards,
Ciobi

Nicola Musatti

unread,
Sep 12, 2007, 1:04:35 PM9/12/07
to
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

Marian Ciobanu

unread,
Sep 13, 2007, 12:49:04 PM9/13/07
to
On Wed, 12 Sep 2007 11:04:35 -0600, Nicola Musatti wrote:

> 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

Right now I still believe what I stated in my prior posts: that SFINAE
only covers template functions, and becase your functions are
non-template, this is not a SFINAE issue. I'll try to start a new
thread to clarify this.

However, I have now a slightly more articulate view about why I think
the code is invalid. The issue is the second fn. When the compiler is
trying to evaluate "value", it has to decide whether it should "call"
the first or the second fn. (Well, it doesn't really call it, it just
needs to know if it can be called, to know the size of the result;
I'll use the word "call" in the rest of the post, but I know that no
actual call is ever made).

GCC 4.2.1 says: "well, classes usually have a public copy constructor,
so I'll just assume X<B> has one as well, so I'll consider the call to
the second fn valid; therefore "value" is always going to be true".

MSVC says: "I don't know who this X<B> is, so I'm just going to ignore
it and consider only the call to the first "fn" as valid and I'll
ignore the second." This doesn't really test if a specialization
exist, though, even assuming the reasoning is correct. Just add this
line after the specialization for X<A>:

template <> class X<B> { X(const X&); };

Now all the compilers will complain that the copy constructor is
private. So a specialization exists but you can't even compile, let
alone test if the specialization exists.

On the other hand, GCC 4.1.0 says: "I don't know who this X<B> is, so
I won't have anything to do with it. I need to know its definition in
order to determine whether I should "call" the second fn or I should
generate a compiler error."

---------------------------------

I think GCC 4.1.0 is right and I find both the GCC 4.2.1 and MSVC 2005
ureasonable (although I'll admit that the standard might actually
state that one of them is correct). I think the second fn can never be
discarded, because it's not a template function. So there are these
options:
- A specialization with a public copy constructor exists, value=true
- A specialization with a non-public copy constructor exists,
compiler error
- A specialization doesn't exists, compiler error

(For replies about whether SFINAE can apply to non-template functions
please use the other thread that I'm going to create, to focus on this
issue alone and leave this thread for finding a solution to
determining whether a specialization of a class exists.)

Ciobi

Carl Barron

unread,
Sep 15, 2007, 10:36:58 AM9/15/07
to
Nicola Musatti <nicola....@gmail.com> wrote:

> Hallo,
> The following program is supposed to use SFINAE to identify whether a
> specific template specialization is defined:
>
> #include <iostream>
> #include <ostream>
>
> class A {};
> class B {};
>
> template <typename T> class X;
>
> template <> class X<A> {};
>
> template <template <typename> class C, typename T> class is_defined {
> typedef char no;
> typedef char (&yes)[2];

why the reference? is size although probably > 1 is dependent on the
compiler while sizeof(char[2]) == 2.
typedef char[2] yes;
looks better.


> static no fn( ... );
> static yes fn(C<T>);

probably should be:
static yes fn(typename C<T> );


> static C<T> const& make();

get rid of the reference make is not really called and then
C<T> must be a complete type.
static C<T> make();


>
> public:
> static const bool value = sizeof( fn( make() ) ) == sizeof(yes);
> };
>

template <template <class>class C,class T>
struct is_defined
{
struct yes {char x[2];};
static char foo(...);
template <class U>
static yes foo(C<U>);
static C<T> make();
public:
const static bool value = sizeof(foo(make())) != 1;
};

looks like it should work. If when this is invoked C<T> is an
incomplete or no existant type then ellisis function is only one
on the valid list and value == false; If C<T> is a complete type
then its on the list for the templated static function and value ==
true;

Not tested.

Seungbeom Kim

unread,
Sep 15, 2007, 7:15:38 PM9/15/07
to
Carl Barron wrote:

> Nicola Musatti <nicola....@gmail.com> wrote:
>
>> template <template <typename> class C, typename T> class is_defined {
>> typedef char no;
>> typedef char (&yes)[2];
>
> why the reference? is size although probably > 1 is dependent on the
> compiler while sizeof(char[2]) == 2.
> typedef char[2] yes;
> looks better.

Maybe, but it makes 'yes' unusable for a return type of a function; the
declaration of 'fn' just below won't work with your definition of 'yes',
because a function can return a reference but not an array.

>> static no fn( ... );
>> static yes fn(C<T>);
> probably should be:
> static yes fn(typename C<T> );

No, C<T> is already known to be a class name from the declaration of the
template parameters. Note that 'typename' expects a qualified name.

--
Seungbeom Kim

Daveed

unread,
Sep 17, 2007, 3:45:26 PM9/17/07
to

I think that error message is correct. You're calling fn with an
lvalue of incomplete type X<B> const. Deduction succeeds (there is
nothing in the SFINAE rules of 14.8.2/2 that would make it fail.) and
overload resolution selects the "yes" candidate. Now you have to
perform the binding (i.e., check the initialization) and you find that
you have to copy an X<B> value, but the type is incomplete: That's an
error.

Daveed

Hendrik Schober

unread,
Sep 20, 2007, 9:18:05 PM9/20/07
to
Daveed <vande...@gmail.com> wrote:
> [...]

> I think that error message is correct. You're calling fn with an
> lvalue of incomplete type X<B> const. Deduction succeeds (there is
> nothing in the SFINAE rules of 14.8.2/2 that would make it fail.) and
> overload resolution selects the "yes" candidate. Now you have to
> perform the binding (i.e., check the initialization) and you find that
> you have to copy an X<B> value, but the type is incomplete: That's an
> error.

Thanks for this clarification. As I don't see how one
can obtain the class' size otherwise, this seems to be
the final nail in this idea's coffin.
ISTR having seen some code that checks for a member's
presence in a class. IIRC, I suppose this would fail
for the same reason (i.e. needs class definition)?

> Daveed

Schobi

--
Spam...@gmx.de is never read
I'm HSchober at gmx dot de
"A patched buffer overflow doesn't mean that there's one less way attackers
can get into your system; it means that your design process was so lousy
that it permitted buffer overflows, and there are probably thousands more
lurking in your code."
Bruce Schneier

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Message has been deleted

Daveed

unread,
Sep 24, 2007, 7:33:11 PM9/24/07
to
On Sep 20, 9:18 pm, "Hendrik Schober" <SpamT...@gmx.de> wrote:

> Daveed<vandevoo...@gmail.com> wrote:
> > [...]
> > I think that error message is correct. You're calling fn with an
> > lvalue of incomplete type X<B> const. Deduction succeeds (there is
> > nothing in the SFINAE rules of 14.8.2/2 that would make it fail.) and
> > overload resolution selects the "yes" candidate. Now you have to
> > perform the binding (i.e., check the initialization) and you find that
> > you have to copy an X<B> value, but the type is incomplete: That's an
> > error.
>
> Thanks for this clarification. As I don't see how one
> can obtain the class' size otherwise, this seems to be
> the final nail in this idea's coffin.
> ISTR having seen some code that checks for a member's
> presence in a class. IIRC, I suppose this would fail
> for the same reason (i.e. needs class definition)?

Correct, the member-test techniques I know of assume the given type is
complete. (Of course, that doesn't make those tricks useless. In
many cases the type must be complete for other reasons.)

Daveed


--

0 new messages