Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > SFINAE to test if a type is streamable, is it possible?

Reply
Thread Tools

SFINAE to test if a type is streamable, is it possible?

 
 
Victor Bogado
Guest
Posts: n/a
 
      03-02-2011
Why does this print "1 1" and not "1 sizeof(int)"?

#include <string>
#include <iostream>

class A {};

template <class C>
struct streamable
{
~streamable()
{
(*static_cast<std:stream*>(0)) <<
(*static_cast<C*>(0));
}
};

template<typename T>
struct is_streamable
{
static char Test(streamable<T>&);
static int Test(...);
static const int value = sizeof(Test((streamable<T>*)(0)));
};

int main()
{
std::cout << is_streamable<A>::value << "\n";
std::cout << is_streamable<int>::value << "\n";
}

 
Reply With Quote
 
 
 
 
James Kanze
Guest
Posts: n/a
 
      03-02-2011
On Mar 2, 4:50 pm, Victor Bogado <bog...@gmail.com> wrote:
> Why does this print "1 1" and not "1 sizeof(int)"?


> #include <string>
> #include <iostream>


> class A {};


> template <class C>
> struct streamable
> {
> ~streamable()
> {
> (*static_cast<std:stream*>(0)) << (*static_cast<C*>(0));


This will result in undefined behavior if the destructor is ever
executed, and the destructor will never be instantiated unless
it is actuall used (and will be executed). Whatever you're
trying to accomplish here, it won't work. (The title mentionned
SFINAE, but of course, that's completely irrelevant with regards
to whatever may be found in the implementation of a member
function.)

> }
> };


> template<typename T>
> struct is_streamable
> {
> static char Test(streamable<T>&);


Requires a reference...

> static int Test(...);
> static const int value = sizeof(Test((streamable<T>*)(0)));


And here you pass a pointer. So function overloading will never
choose the first function above.

> };


> int main()
> {
> std::cout << is_streamable<A>::value << "\n";
> std::cout << is_streamable<int>::value << "\n";
> }


Maybe because on your machine sizeof(int) is 1?

I get "4 4" on my Linux box, which is what I'd expect. As
written, there's no code which will ever match the first Test.

If you're trying to distinguish which objects have a << defined
for them, that's something else entirely. Somewhere, you need
a template function declaration whose instantiation depends on
the expression x<<y. Something like:

template <typename T, size_t> struct D{};

template <typename T>
struct is_streamable
{
template <typename U> static char Test(
U*, D<U, sizeof( std::cout << *(static_cast<U*>( 0 )) )>* );
template <typename U> static int Test(U*, ...);
static const int value = sizeof( Test<T>( 0, 0 ) );
};

int main()
{
std::cout << is_streamable<A>::value << "\n";
std::cout << is_streamable<int>::value << "\n";
return 0;
}

Anyway, with the necessary includes added, this compiles and
outputs 4 1 with g++. Not with VC++ (VS , however; I suspect that
this is a bug in VC++, but I'm too busy right now to dig into
the standard to be sure. Anyway, SFINAE only comes into play
when attempting to instantiate a function template, so you need
something which gets the expression into a function template
parameters.

--
James Kanze
 
Reply With Quote
 
 
 
 
Victor Bogado
Guest
Posts: n/a
 
      03-03-2011
On Mar 2, 3:35*pm, James Kanze <james.ka...@gmail.com> wrote:
> On Mar 2, 4:50 pm, Victor Bogado <bog...@gmail.com> wrote:
>
> > Why does this print "1 1" and not "1 sizeof(int)"?
> > #include <string>
> > #include <iostream>
> > class A {};
> > template <class C>
> > struct streamable
> > {
> > * * * ~streamable()
> > * * * {
> > * * * * * * * (*static_cast<std:stream*>(0)) << (*static_cast<C*>(0));

>
> This will result in undefined behavior if the destructor is ever
> executed, and the destructor will never be instantiated unless
> it is actuall used (and will be executed). *Whatever you're
> trying to accomplish here, it won't work. *(The title mentionned
> SFINAE, but of course, that's completely irrelevant with regards
> to whatever may be found in the implementation of a member
> function.)


This was one of several attempts I made, none of them worked .
But the idea was that this class would never be instantiated, the
compiler should only check if he can instantiate or not. My guess
is that with the code above that destructor is never called. Never
the less, it would be wise not to leave such code in a production
environment (this was just a test).

>
> > * * * }
> > };
> > template<typename T>
> > struct is_streamable
> > {
> > * * * static char Test(streamable<T>&);

>
> Requires a reference...
>
> > * * * static int Test(...);
> > * * * static const int value = sizeof(Test((streamable<T>*)(0)));

>
> And here you pass a pointer. *So function overloading will never
> choose the first function above.


You're right, but this might be an error on the post, since my test
output was "1 1" and not "4 4". Weird, I may have tested with other
version, as I said I made several tests and posted one, so I could
get help here.

>
> > };
> > int main()
> > {
> > * * * std::cout << is_streamable<A>::value << "\n";
> > * * * std::cout << is_streamable<int>::value << "\n";
> > }

>
> Maybe because on your machine sizeof(int) is 1?


My machine is a linux in a 64bit environment. sizeof(int) is not 1.

>
> I get "4 4" on my Linux box, which is what I'd expect. *As
> written, there's no code which will ever match the first Test.
>
> If you're trying to distinguish which objects have a << defined
> for them, that's something else entirely. *Somewhere, you need
> a template function declaration whose instantiation depends on
> the expression x<<y. *Something like:
>
> * * * * template <typename T, size_t> struct D{};
>
> * * * * template <typename T>
> * * * * struct is_streamable
> * * * * {
> * * * * * * * * template <typename U> static char Test(
> * * * * * * * * * * * * U*, D<U, sizeof( std::cout << *(static_cast<U*>( 0 )) )>* );
> * * * * * * * * template <typename U> static int Test(U*,...);
> * * * * * * * * static const int value = sizeof( Test<T>( 0, 0 ) );
> * * * * };
>
> * * * * int main()
> * * * * {
> * * * * * * * * std::cout << is_streamable<A>::value << "\n";
> * * * * * * * * std::cout << is_streamable<int>::value <<"\n";
> * * * * * * * * return 0;
> * * * * }
>
> Anyway, with the necessary includes added, this compiles and
> outputs 4 1 with g++. *Not with VC++ (VS , however; I suspect that
> this is a bug in VC++, but I'm too busy right now to dig into
> the standard to be sure. *Anyway, SFINAE only comes into play
> when attempting to instantiate a function template, so you need
> something which gets the expression into a function template
> parameters.


I will use it with boost::enable_if to enable or disable a method on a
class. Unfortunately, this don't work with g++ version 4.1.2, the
compiler only attempts to instantiate the first version. But it does
work in the g++ 4.4.0.

>
> --
> James Kanze


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-03-2011
On Mar 3, 1:07 pm, Victor Bogado <bog...@gmail.com> wrote:
> On Mar 2, 3:35 pm, James Kanze <james.ka...@gmail.com> wrote:
> > On Mar 2, 4:50 pm, Victor Bogado <bog...@gmail.com> wrote:


> > > Why does this print "1 1" and not "1 sizeof(int)"?
> > > #include <string>
> > > #include <iostream>
> > > class A {};
> > > template <class C>
> > > struct streamable
> > > {
> > > ~streamable()
> > > {
> > > (*static_cast<std:stream*>(0)) << (*static_cast<C*>(0));


> > This will result in undefined behavior if the destructor is ever
> > executed, and the destructor will never be instantiated unless
> > it is actuall used (and will be executed). Whatever you're
> > trying to accomplish here, it won't work. (The title mentionned
> > SFINAE, but of course, that's completely irrelevant with regards
> > to whatever may be found in the implementation of a member
> > function.)


> This was one of several attempts I made, none of them worked .
> But the idea was that this class would never be instantiated, the
> compiler should only check if he can instantiate or not.


The compiler will have no problem instantiating the class, since
all it contains is a destructor. The compiler will not be able
to instantiate the destructor definition. And there's no
context where failing to instantiate a function definition is
not an error.

> My guess is that with the code above that destructor is never
> called. Never the less, it would be wise not to leave such
> code in a production environment (this was just a test).


> > > }
> > > };
> > > template<typename T>
> > > struct is_streamable
> > > {
> > > static char Test(streamable<T>&);


> > Requires a reference...


> > > static int Test(...);
> > > static const int value = sizeof(Test((streamable<T>*)(0)));


> > And here you pass a pointer. So function overloading will never
> > choose the first function above.


> You're right, but this might be an error on the post, since my test
> output was "1 1" and not "4 4". Weird, I may have tested with other
> version, as I said I made several tests and posted one, so I could
> get help here.


>
> > > };
> > > int main()
> > > {
> > > std::cout << is_streamable<A>::value << "\n";
> > > std::cout << is_streamable<int>::value << "\n";
> > > }


> > Maybe because on your machine sizeof(int) is 1?


> My machine is a linux in a 64bit environment. sizeof(int) is not 1.


So you must have tested something else. I both expected and got
4 4. On a Linux machine (not sure if the environment was 32 bit
or 64, but it shouldn't matter).

> > I get "4 4" on my Linux box, which is what I'd expect. As
> > written, there's no code which will ever match the first Test.


> > If you're trying to distinguish which objects have a << defined
> > for them, that's something else entirely. Somewhere, you need
> > a template function declaration whose instantiation depends on
> > the expression x<<y. Something like:


> > template <typename T, size_t> struct D{};


> > template <typename T>
> > struct is_streamable
> > {
> > template <typename U> static char Test(
> > U*, D<U, sizeof( std::cout << *(static_cast<U*>( 0 )) )>* );
> > template <typename U> static int Test(U*, ...);
> > static const int value = sizeof( Test<T>( 0, 0 ) );
> > };


> > int main()
> > {
> > std::cout << is_streamable<A>::value << "\n";
> > std::cout << is_streamable<int>::value << "\n";
> > return 0;
> > }


> > Anyway, with the necessary includes added, this compiles and
> > outputs 4 1 with g++. Not with VC++ (VS , however; I suspect that
> > this is a bug in VC++, but I'm too busy right now to dig into
> > the standard to be sure. Anyway, SFINAE only comes into play
> > when attempting to instantiate a function template, so you need
> > something which gets the expression into a function template
> > parameters.


> I will use it with boost::enable_if to enable or disable a method on a
> class. Unfortunately, this don't work with g++ version 4.1.2, the
> compiler only attempts to instantiate the first version. But it does
> work in the g++ 4.4.0.


My tests were run with g++ 4.4.2.

--
James Kanze
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
SFINAE -- basis: array of void is invalid type Barry C++ 2 05-29-2008 03:43 PM
type function U[1] and U(*)[1] SFINAE issue Fei Liu C++ 5 05-29-2008 05:42 AM
Is a class type using SFINAE siddhu C++ 1 05-17-2007 05:21 PM
problem with SFINAE applied to class methods Peter Collingbourne C++ 8 07-04-2004 07:25 PM
test test test test test test test Computer Support 2 07-02-2003 06:02 PM



Advertisments