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

Detecting a specific member function is defined

241 views
Skip to first unread message

Brian Ross

unread,
Mar 10, 2003, 9:58:39 PM3/10/03
to
Hi,

I have seen some tidbits of information on this topic but I can't seem to
find enough to answer my question so I am going to post here with the hope
that someone can answer my question in a way I can understand :)

What I would like to do is have a template that can perform some action if a
class has a particular member function and some other action otherwise.
Ideally this detection would be done by the compiler in order to call the
correct function. I think the best way to explain exactly what I mean would
be an example:

Lets say I have a template swap function (go figure :) ):

template <typename T>
void Swap(T& Value1, T& Value2);

Ideally I would like the implementation to be:

template <typename T>
void Swap(T& Value1, T& Value2) throw();
{
Value1.Swap(Value2); // non throwing efficient swap of internal members
}

but this requires that the class has a member function 'Swap' with the
following signature:

class Obj
{
public:
void Swap(Obj& Value) throw(); // non throwing efficient swap of
internal members
}

This means that classes that don't meet this critera (as well as built in
types) will generate a compiler error.

What would be ideal is if I could provide a second implementation for types
which do not have a function that matches that criteria:

template <typename T>
void Swap(T& Value1, T& Value2)
{
T& Temp(Value1); Value1 = Value2; Value2 = Temp; // might throw - not
guaranteed to be efficient
}

Then the compiler would 'detect' if the first one is acceptable otherwise
call the second version.

Some notes:

1 - I am pretty sure I can think of a way to fake this using inheritance but
that places more restrictions on how the classes which use the first version
are designed.
2 - Ideally one would not be forced to provide one Swap implementation and
then provide specializations for each any every class that does not satisfy
the requirements of that version - the goal is to let the compiler do the
work.

Thanks for any information anyone can offer :)


Ioannis Vranos

unread,
Mar 10, 2003, 10:23:18 PM3/10/03
to
"Brian Ross" <brian....@rogers.com> wrote in message
news:zhcba.221093$Zr%.218124@news01.bloor.is.net.cable.rogers.com...


Check the standard library. It even provides a generic swap function. An
excellent book to read is "The C++ Programming Language" 3rd Edition or
Special Edition by Bjarne Stroustrup (the creator of C++).


--
Ioannis

* Programming pages: http://www.noicys.freeurl.com
* Alternative URL: http://run.to/noicys

Phlip

unread,
Mar 10, 2003, 11:26:58 PM3/10/03
to
Ioannis Vranos sez:

> Brian Ross wrote:

> > ...I think the best way to explain exactly what I mean
> would
> > be an example:

> > Lets say I have a template swap function (go figure :) ):

> Check the standard library. It even provides a generic swap function. An


> excellent book to read is "The C++ Programming Language" 3rd Edition or
> Special Edition by Bjarne Stroustrup (the creator of C++).

Ioannis, read the question next time. "Swap" was just the example; std::swap
doesn't do what he needs.

Brian, I wasn't going to answer if all I could have offered is /Modern C++
Design: Generic Programming and Design Patterns Applied/ by Andrei
Alexandrescu.

Here's probably his chapter on the Policy template concept:

http://www.accu-usa.org/Slides/moderndesign.ppt

--
Phlip
http://www.greencheese.org/MayorZogg
"A DB makes data readily available for all systems in the enterprise to
brutally couple themselves to each other's private parts."
-- Klaus Wuestefeld


Ioannis Vranos

unread,
Mar 10, 2003, 11:44:47 PM3/10/03
to
"Phlip" <phli...@yahoo.com> wrote in message
news:b4joii$d...@dispatch.concentric.net...

> Ioannis Vranos sez:
>
> > Brian Ross wrote:
>
> > > ...I think the best way to explain exactly what I mean
> > would
> > > be an example:
>
> > > Lets say I have a template swap function (go figure :) ):
>
> > Check the standard library. It even provides a generic swap function. An
> > excellent book to read is "The C++ Programming Language" 3rd Edition or
> > Special Edition by Bjarne Stroustrup (the creator of C++).
>
> Ioannis, read the question next time. "Swap" was just the example;
std::swap
> doesn't do what he needs.
>
> Brian, I wasn't going to answer if all I could have offered is /Modern C++
> Design: Generic Programming and Design Patterns Applied/ by Andrei
> Alexandrescu.
>
> Here's probably his chapter on the Policy template concept:
>
> http://www.accu-usa.org/Slides/moderndesign.ppt


TC++PL has everything he needs. It says how standard containers work, the
algorithms they are provided, design principles, etc. For exampe he seems to
not know that the default comparison criteria to generic algorithms is <, so
he has to provide an operator<.

Phlip

unread,
Mar 11, 2003, 12:04:18 AM3/11/03
to
Ioannis Vranos sez:

> TC++PL has everything he needs. It says how standard containers work, the
> algorithms they are provided, design principles, etc. For exampe he seems
to
> not know that the default comparison criteria to generic algorithms is <,
so
> he has to provide an operator<.

Brian is not writing a Swap function.

He wants a template that expands one way if its argument has a given method,
and another way if it does not. I honestly can't tell if you read the same
post as I.

There probably is no way to do what he wants without passing some kind of
extra template into the main template. So, if he needed to Foo instead of
Swap, he'd write one of:

Foo<MyAclass, policyWithMethod>();
Foo<MyBclass, policyWithoutMethod>();

Now the question becomes this: How do you make the template automatically
select one or the other policy? The answer is you can't.

If Brian used the Traits pattern, he'd need to custom instantiate a
different trait for each class he intended to pass into Foo. Without other
clients for those traits this adds complexity without purpose.

Switch to a language like Ruby where you can query for the existence of a
method, and you can compile a call to one that doesn't exist, even if you
can't run it.

--
Phlip
http://www.greencheese.org/NotScudds
-- you say "delusional psychosis"
like it was a _bad_ thing... --


Aaron Anodide

unread,
Mar 11, 2003, 12:50:56 AM3/11/03
to

"Brian Ross" <brian....@rogers.com> wrote in message
news:zhcba.221093$Zr%.218124@news01.bloor.is.net.cable.rogers.com...

Well, for your swap example (and I realize this just one example), you would
accomplish the same thing by overloading the = operator and just using the
second form of your function. Maybe for other times you want this special
template feature you can come up with either an operator overload or an
explicit type conversion to get the same result.

Another, totally off the wall thing you can do, because hey, nobody will
actually stop you, is write a wacked out pre-pre-processor in perl and
devise a custom token, thus doing your own simple template expansion. Of
course you'd have to parse all your c++ headers to get the required info...
maybe I've had enough coffee for one night.

Aaron

Ioannis Vranos

unread,
Mar 11, 2003, 2:37:14 AM3/11/03
to
"Phlip" <phli...@yahoo.com> wrote in message
news:b4jqoi$d...@dispatch.concentric.net...

>
> Brian is not writing a Swap function.
>
> He wants a template that expands one way if its argument has a given
method,
> and another way if it does not. I honestly can't tell if you read the same
> post as I.
>
> There probably is no way to do what he wants without passing some kind of
> extra template into the main template. So, if he needed to Foo instead of
> Swap, he'd write one of:
>
> Foo<MyAclass, policyWithMethod>();
> Foo<MyBclass, policyWithoutMethod>();
>
> Now the question becomes this: How do you make the template automatically
> select one or the other policy? The answer is you can't.
>
> If Brian used the Traits pattern, he'd need to custom instantiate a
> different trait for each class he intended to pass into Foo. Without other
> clients for those traits this adds complexity without purpose.
>
> Switch to a language like Ruby where you can query for the existence of a
> method, and you can compile a call to one that doesn't exist, even if you
> can't run it.


Unavoidably he will have to use some run-time type identification (which
means the function will not be generic). For example:

class no_member
{
// ...
};


class whatever:public no_member
{
// ...
}


template<class T>
void whatever(T *p)
{
// If it is with no member...
if(dynamic_cast<no_member *>(p))
{
// ...
}

else // ...
}


If he doesn't like inheritance he can use a flag:


template <class T>
void whatever(T &r, bool member_mode=false)
{
// If there is no member
if(!mode)
{
// ...
}

else // ...
}


Usage:

someclass obj;

whatever(obj);


some_other_class psi;

whatever(psi, true);


I am sure there many other things one can do.

Paul Mensonides

unread,
Mar 11, 2003, 3:13:47 AM3/11/03
to
Ioannis Vranos wrote:
> "Phlip" <phli...@yahoo.com> wrote in message
> news:b4jqoi$d...@dispatch.concentric.net...
>>
>> Brian is not writing a Swap function.
>>
>> He wants a template that expands one way if its argument has a given
>> method, and another way if it does not. I honestly can't tell if you
>> read the same post as I.
>>
>> There probably is no way to do what he wants without passing some
>> kind of extra template into the main template. So, if he needed to
>> Foo instead of Swap, he'd write one of:
>>
>> Foo<MyAclass, policyWithMethod>();
>> Foo<MyBclass, policyWithoutMethod>();
>>
>> Now the question becomes this: How do you make the template
>> automatically select one or the other policy? The answer is you
>> can't.

Yes, you can:

#include <iostream>

template<class T> struct has_member_Swap;

template<class R, class C> class has_member_Swap<R C::*> {
private:
template<R C::*> struct helper;
template<class T> static char check(helper<&T::Swap>*);
template<class T> static char (& check(...))[2];
public:
enum { value = sizeof(check<C>(0)) == 1 };
};

struct A { };

struct B {
void Swap(B&) throw();
};

int main() {
std::cout
<< has_member_Swap<void (A::*)(A&) throw()>::value << '\n';
<< has_member_Swap<void (B::*)(B&) throw()>::value << &std::endl;
return 0;
}

Deduction by SFINAE. Non-class types can be excluded via:

template<class T> class is_class {
private:
template<class U> static char check(int U::*);
template<class U> static char (& check(...))[2];
public:
enum { value = sizeof(check<T>(0)) == 1 };
};

Regards,
Paul Mensonides

Ioannis Vranos

unread,
Mar 11, 2003, 3:26:00 AM3/11/03
to
"Paul Mensonides" <leav...@attbi.com> wrote in message
news:%Ugba.36183$eG2.7274@sccrnsc03...

That's nice. However why i see it as an answer to my post?

Paul Mensonides

unread,
Mar 11, 2003, 9:33:54 AM3/11/03
to
Ioannis Vranos wrote:

[...]

> That's nice. However why i see it as an answer to my post?

Sorry, it was an answer to both your post and Phlip's post. No RTTI is
necessary, neither is an external traits class.

Regards
Paul Mensonides


Phlip

unread,
Mar 11, 2003, 9:56:44 AM3/11/03
to
"Paul Mensonides" <leav...@attbi.com> wrote in message
news:%Ugba.36183$eG2.7274@sccrnsc03...

> Yes, you can:


>
> #include <iostream>
>
> template<class T> struct has_member_Swap;
>
> template<class R, class C> class has_member_Swap<R C::*> {
> private:
> template<R C::*> struct helper;
> template<class T> static char check(helper<&T::Swap>*);
> template<class T> static char (& check(...))[2];
> public:
> enum { value = sizeof(check<C>(0)) == 1 };
> };

This turn the existence of Swap into a boolean. (And thanks - I was unaware
of the idiom). So put the

int const mode = has_member_Swap<T>::value;

But now what do you do with it? Ioannis suggested this:

> if(!mode)
> {
> // ...
> }
>
> else // ...

But the problem is C++ will compile every line of a template. Both branches
of the if. So if one branch says Swap it will still compile - especially if
'mode' is not a compile-time constant.

Now if Paul can make that 'mode' a hard constant, and if we call a method
that calls Swap, and if the method is a template declared out-of-line, I
don't know if the compiler will compile it or not. If it compiles a method
instance that will never be called, it will still complain there's no Swap.

So the best way I can think of is >another< template:

selectSwap<mode>(*this);

Write two instances of that function; one calls Swap and the other does not.

We have a winner!

--
Phlip
http://www.greencheese.org/LucidScheming
-- Why is the "Cheesy Horror Movie Channel"
called "SciFi"?? --


Aaron Anodide

unread,
Mar 11, 2003, 11:51:17 AM3/11/03
to

"Paul Mensonides" <leav...@attbi.com> wrote in message
news:%Ugba.36183$eG2.7274@sccrnsc03...
> Ioannis Vranos wrote:
> > "Phlip" <phli...@yahoo.com> wrote in message
> > news:b4jqoi$d...@dispatch.concentric.net...
> >>
> >> Brian is not writing a Swap function.
> >>
> >> He wants a template that expands one way if its argument has a given
> >> method, and another way if it does not. I honestly can't tell if you
> >> read the same post as I.
> >>
> >> There probably is no way to do what he wants without passing some
> >> kind of extra template into the main template. So, if he needed to
> >> Foo instead of Swap, he'd write one of:
> >>
> >> Foo<MyAclass, policyWithMethod>();
> >> Foo<MyBclass, policyWithoutMethod>();
> >>
> >> Now the question becomes this: How do you make the template
> >> automatically select one or the other policy? The answer is you
> >> can't.
>
> Yes, you can:
>
> #include <iostream>
>
> template<class T> struct has_member_Swap;
>
> template<class R, class C> class has_member_Swap<R C::*> {

What's the deal with C::* ? I've never seen that before.

Thanks,
Aaron

Victor Bazarov

unread,
Mar 11, 2003, 12:24:08 PM3/11/03
to
"Aaron Anodide" <ano...@hotmail.com> wrote...

> "Paul Mensonides" <leav...@attbi.com> wrote in message
> news:%Ugba.36183$eG2.7274@sccrnsc03...
> > template<class R, class C> class has_member_Swap<R C::*> {
>
> What's the deal with C::* ? I've never seen that before.


C::* is 'a pointer to member of C'. 'R C::*' means "a pointer
to a member of C of type R".

Victor
--
Please remove capital A's from my address when replying by mail


0 new messages