Topic: Are these likely to be a legitimate use of typeof?


Author: usenet@hgardner.com (Howard Gardner)
Date: Sat, 5 Feb 2005 04:00:53 GMT
Raw View
I've been writing functors. Typeof would make this so much easier. I
think. Is it still expected to be in the next standard? If so, is it
going to work the way it would need to work for the code below to compile?

The numbers are either arities or positions in the argument list, depending.

Please overlook typos. I can't compile this :)

// newfangled deducer, never defined
template< typename xResult >
xResult deduce_result(xResult (*)());

// newfangled deducer, never defined
template< typename xResult, typename xArg01 >
xArg1 deduce_01(xResult (*)(xArg1));

// newfangled ftor, relying on typeof and deducers
template < typename xCallable >
struct nf_ftor_00
{
   typedef xCallable tCallable;
   typedef typeof(deduce_result(xCallable)) tResult;
   tResult operator () const;
};

// newfangled ftor, relying on typeof and deducers
template < typename xCallable >
struct nf_ftor_01
{
   typedef xCallable tCallable;
   typedef typeof(deduce_result(xCallable)) tResult;
   typedef typeof(deduce_01(xCallable)) tArg01;
   tResult operator()(tArg01) const;
};

// newfangled deducer, never defined
template< typename xResult >
nf_ftor_00< xResult (*)() >
deduce_ftor(xResult (*)());

// newfangled deducer, never defined
template< typename xResult, typename xArg01 >
nf_ftor_01< xResult (*)(xArg01) >
deduce_ftor(xResult (*)(xArg01));

// old fashioned ftor
template < typename xCallable, typename xResult >
struct of_ftor_00
{
   typedef xCallable tCallable;
   typedef xResult tResult;
   tResult operator () const;
};

// old fashioned maker
template< typename xResult >
of_ftor_00< xResult (*)(), xResult > make_of_ftor(xResult (*)());

bool func_bool_00();
bool func_bool_01(bool);

int main()
{
   // A nice direct declaration
   nf_ftor_00< func_bool_00 > fA;

   // Salvaging existing ftor production schemes
   typeof(make_of_ftor(func_bool_00)) fB;

   // Making arity easy to manage
   typeof(deduce_ftor(func_bool_00)) fC;
   typeof(deduce_ftor(func_bool_01)) fD;
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Mon, 7 Feb 2005 18:57:11 GMT
Raw View
Howard Gardner wrote:
> I've been writing functors. Typeof would make this so much easier. I
> think. Is it still expected to be in the next standard? If so, is it
> going to work the way it would need to work for the code below to compile?
>
 > ...

I believe you are referring to something I proposed here some
time ago.  I do not recall seeing any formal commitment to include
it in the new standard but I do not remember any really strong
objections.  I recall that someone figured out how to do the
same thing without using a new keyword.  I also recall a mention
that gcc had implemented such a keyword prior to my bringing it
up here.  There was also a hiatus since then where I did not
follow this NG and there may have been other discussions in that
hiatus.

Given all that qualification on my qualifications I tentatively
answer your question as follows:

That sure looks like what I intended 'typeof' to do, among
other things.

max@mtew.isa-geek.net

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Entwicklung@reico.de (Olaf Krzikalla)
Date: Tue, 8 Feb 2005 18:07:07 GMT
Raw View
Hi,

At a first glance I don't think, that you'd need typeof to achieve these
things. Have a look at the template arg_deducer in Message-ID:
<41179A64.1CF0D9AA@reico.de>, where I deduce function arguments (you can
do the same with function results) using standard C++ only (well, there
is a missing typename later on).

Best regards
Olaf Krzikalla

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: usenet@hgardner.com (Howard Gardner)
Date: Thu, 10 Feb 2005 17:16:32 GMT
Raw View
===================================== MODERATOR'S COMMENT:

Please quote an appropriate amount of context in a conventional format
when posting replies to messages.


===================================== END OF MODERATOR'S COMMENT
/*
That's a neat way to address the fact that a template
function will deduce a pass by value even when you
feed it a reference.

It doesn't solve my problem, though: I can't compile
the line of code that's commented out below.

A function like deduce_res is the normal workaround.
It results in a mountain of code though.

I've experimented with a solution based on sizeof and
arrays, but it appears to scale badly. I included a
sketch of it anyway. (the stuff named bt_xxx).

I see four problems with it:

1) It requires both a bt_data and a bt_type specialization
for every type that I want to be able to get the type of.
For this to be of any value to me, I'd have to be able to
get the types of user-defined classes. That means that users
would have to do work, and puts it in the "fat chance"
category.

2) I might have gone that direction anyway, except that
the the bt_data specializations include a magic constant
that must be unique for every one of them. Administering
that magic constant would be hellish.

3) I'm not even positive that the technique is standard.
It seems to me that sizeof(bt_data<void>) must be unique
amongs the bt_data specializations, but I'm not sure.

4) It's definitely not safe to rely on in code that uses
different compilers. There's a whole slew of caveats
hanging off of that obtervation.

Your technique might help reduce code size for someone
who goes off in that direction. It won't make the
scaling any better though.

As far as I can find out, the only solutions currently
available are to use template argument deduction, which
results in mountains of code, or to use a variant of
the bt technique. Typeof--assuming it works the way
I expect--would make the mountains of code go away,
and it would scale better :)

In other words: yes, I DO need it!
*/
#include <cstddef>

void sample_void(){}

bool sample_bool(){return false;}

int sample_int(){return 0;}

template < typename xRes >
struct deducer_res;

template < typename xRes >
struct deducer_res< xRes (*)() >
{
   typedef xRes tRes;
};

template < typename xCallable >
void
deduce_res
(
   xCallable
)
{
   typedef typename deducer_res< xCallable >::tRes tRes;
}

template< typename xType >
struct bt_data;

template< >
struct bt_data< void >
{
   typedef char tArray[1];
   tArray cArray;
};

template< >
struct bt_data< bool >
{
   typedef char tArray[2];
   tArray cArray;
};

template< >
struct bt_data< int >
{
   typedef char tArray[3];
   tArray cArray;
};

template< size_t xCase >
struct bt_type;

template< >
struct bt_type< sizeof(bt_data< void >) >
{
   typedef bool tType;
};

template< >
struct bt_type< sizeof(bt_data< bool >) >
{
   typedef bool tType;
};

template< >
struct bt_type< sizeof(bt_data< int >) >
{
   typedef int tType;
};

template< typename xRes >
bt_data< xRes >
bt_res(xRes (*)());

int main()
{
// typedef deducer_res< sample_void >::tRes tVoid;
// typedef deducer_res< sample_bool >::tRes tBool;
// typedef deducer_res< sample_int >::tRes tInt;

   deduce_res(sample_void);
   deduce_res(sample_bool);
   deduce_res(sample_int);

  typedef bt_type< sizeof(bt_res(sample_void)) >::tType tVoid;
  typedef bt_type< sizeof(bt_res(sample_bool)) >::tType tBool;
  typedef bt_type< sizeof(bt_res(sample_int)) >::tType tInt;

   return 0;
}

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Entwicklung@reico.de (Olaf Krzikalla)
Date: Sat, 12 Feb 2005 19:13:55 GMT
Raw View
Hi,

Howard Gardner schrieb:
> It doesn't solve my problem, though: I can't compile
> the line of code that's commented out below.
> ...
> void sample_void(){}
> ...
> // typedef deducer_res< sample_void >::tRes tVoid;
You use an expression to instantiate deducer_res, but you actually need
a type. ATM an automatic type deduction from an expression can be done
by function templates only (AFAIK and baring sizeof). And I don't think,
the sizeof approach leads to anything useful. The following (slightly
extended) code can be taken as a base (Comeau compiles it):

#include <iostream>
#include <ostream>

void int_fp (int a)
{
  std::cout << "int-Version used";
}

int int_fpr (int& a)
{
  std::cout << "ref-Version used";
  return a;
}

int bla();

template<class T>
struct arg_deducer;

template<class T>
struct arg_deducer<T (*)()>
{
  typedef T res;
};

template<class T, class U>
struct arg_deducer<T (*)(U)>
{
  typedef T res;
  typedef U arg;
};

template<class T>
typename arg_deducer<T>::res call (T fp, typename arg_deducer<T>::arg a)
{
  return fp (a);
}

template<class T>
typename arg_deducer<T>::res call (T fp)
{
  return fp();
}

int main()
{
  int a = 0;
  call (int_fp, a);
  a = call (int_fpr, a);
  a = call (bla);
  std::cin.ignore();
  return 0;
}


Related to your original problem, you could rewrite e.g.:

template< typename xResult >
typename arg_deducer<xResult>::res deduce_ftor(xResult f);

Of course, declaring deduce_ftor directly would cause some trouble now
(in fact, you are better suited with typeof in this case), but I'm not
sure, if this is the problem actually to solve. Maybe you can post a
little application of one of your functors.


Best regards
Olaf Krzikalla

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: usenet@hgardner.com (Howard Gardner)
Date: Sun, 13 Feb 2005 02:17:30 GMT
Raw View
Olaf Krzikalla wrote:
> Hi,
>
> Howard Gardner schrieb:
>
>>It doesn't solve my problem, though: I can't compile
>>the line of code that's commented out below.
>>...
>>void sample_void(){}
>>...
>>// typedef deducer_res< sample_void >::tRes tVoid;
>
> You use an expression to instantiate deducer_res, but you actually need
> a type. ATM an automatic type deduction from an expression can be done
> by function templates only (AFAIK and baring sizeof). And I don't think,
> the sizeof approach leads to anything useful.

The list of caveats is pretty long. If the set of potential types to be
was is small it might be useful. My set is unbounded :0

The following (slightly
> extended) code can be taken as a base (Comeau compiles it):
>
> ...
 >
> Related to your original problem, you could rewrite e.g.:
>
> template< typename xResult >
> typename arg_deducer<xResult>::res deduce_ftor(xResult f);
>
> Of course, declaring deduce_ftor directly would cause some trouble now
> (in fact, you are better suited with typeof in this case), but I'm not
> sure, if this is the problem actually to solve. Maybe you can post a
> little application of one of your functors.
>

The problem is to construct a functor given "some mechanism" and a
callable entity. Extra credit for doing it without calling a function at
run time ;)

I know that the problem is solvable because I've solved it several
times. It's the extra credit that I'm after, and I'm pretty convinced
that it's not to be had unless we get typeof.

The mechanism that I've used revolves around "make_ftor."

template< typename xCallable, typename xRes >
ftor_free_00< xRes > make_ftor(xRes (*)());

template< typename xCallable, typename xRes, typename xArg01 >
ftor_free_01< xRes, xArg01 > make_ftor(xRes (*)(xArg01));

And so on.

I didn't know the trick you showed me, so I've never used it when I
implemented make_ftor before. I'm doing another implementation now. It
uses your trick and a purpose-built type list. So far, it appears that
this implementation is going to be a lot (order of magnitude) shorter
than any of the previous implementations that I've done.

It appears to me that the size of an implementation of make_ftor is
exponential in the number of arities that it covers: doubling the number
of arities more than doubles the size of the implementation. While this
new implementation is going to be much shorter than the old one,
extending it will still be a fight against exponential growth. This is
mitigated by the fact that an implementation that covers arities of 0-7
(or 0-15) is useful, and the marginal utility of adding another arities
beyond those dwindles rapidly. I expect to be content with my new
implementation.

I won't be happy with it though. It results in a spurious (for a given
value of spurious) function call, and it forces me to make more such
function calls. For example:

std::make_pair(make_ftor(foo), make_ftor(bar));

If I had typeof, I'd write:

std::pair< ftor< typeof(foo) >, ftor< typeof(bar) >(foo, bar);

which involves fewer function calls.

Those function calls would vaporize if the compiler is doing any
optimizing and xCallable is a function pointer. If xCallable is a
functor, though, it may have state that is nontrivial to copy. I can
combat that with pimpl, but then I'm buying a ticket in the optimization
lottery by guaranteeing some unknowable number of extra pointer
dereferences.

By the way, I completely misunderstood the way your trick worked until I
had played with it for a while. I think this code is clearer for
explanation:

template < typename xCallable >
struct deducer;

template < typename xRes >
struct deducer< xRes (*)() >;

template < typename xRes, xArg01 >
struct deducer< xRes (*)(xArg01) >;

template < typename xRes, xClass >
struct deducer< xRes (xClass::*)() >;

It amazes me that it works. Heh.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: usenet@hgardner.com (Howard Gardner)
Date: Sun, 13 Feb 2005 21:20:09 GMT
Raw View
Howard Gardner wrote:
>
> By the way, I completely misunderstood the way your trick worked until I
> had played with it for a while. I think this code is clearer for
> explanation:
>
> template < typename xCallable >
> struct deducer;
>
> template < typename xRes >
> struct deducer< xRes (*)() >;
>
> template < typename xRes, xArg01 >
> struct deducer< xRes (*)(xArg01) >;
>
> template < typename xRes, xClass >
> struct deducer< xRes (xClass::*)() >;
>
> It amazes me that it works. Heh.

Well, it would have been if it hadn't been wrong :/

template < typename xCallable >
struct deducer;

template < typename xRes >
struct deducer< xRes (*)() >;

template < typename xRes, typename xArg01 >
struct deducer< xRes (*)(xArg01) >;

template < typename xRes, typename xClass >
struct deducer< xRes (xClass::*)() >;

template < typename xRes, typename xClass >
struct deducer< xRes (xClass::*)() const >;

template < typename xRes, typename xArg01, typename xArg02 >
struct deducer< xRes (*)(xArg01, xArg02) >;

template < typename xRes, typename xClass, typename xArg02 >
struct deducer< xRes (xClass::*)(xArg02) >;

template < typename xRes, typename xClass, typename xArg02 >
struct deducer< xRes (xClass::*)(xArg02) const >;

As penance, I'll try an explanation myself :)

The original template is deducer. It takes one parameter, which is
presumably a callable entity.

The specializations of deducer provide that callable entity:

xRes (*)()
xRes (*)(xArg01)
xRes (xClass::*)()
xRes (xClass::*)() const

and so forth.

The template parameter list for a specialization is different from the
template parameter list for the original template. The parameter list
for a specialization includes the return type for the callable entity
(xRes) and all of the types in its signature (xArg01, xArg02, etc.). For
class member functions, it also includes the class (xClass) and its
constness or nonconstness (const or nothing).

I misunderstood the original implementation because I didn't realize
that the template argument lists were different.

With a set of deducers like this in hand, I no longer need to write
multiple make_ftors. This suffices:

template < class xCallable >
ftor< xCallable >
make_ftor
(
   xCallable fCallable
)
{
  return ftor< xCallable >();
}

Now the complexity is buried in the definition of:

template < typename xCallable > class ftor;

One version of make_ftor instead of 8 (for free functions) + 7 (for
nonconst member functions) + 7 (for const member functions) + 1 (for
things that are already ftors) = 24. Much better :)

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]