Topic: Finding the return type of a function, hassles with traits.


Author: "Steve R. Karmesin" <ssr@cacr.caltech.edu>
Date: 1996/10/24
Raw View
As has been pointed out in the recent thread on Return Value and
Function's Signature, the name of a function and the types of its
arguments fully specifies the return type of the function.

A problem I'm coming across is that I want to know that type.  Consider
the following code:

    class A {};
    class B {};
    class C {};
    class AB {};
    class BC {};
    class AC {};
    class BA {};
    class CB {};
    class CA {};

    AB f(A,B) { return AB(); }
    AC f(A,C) { return AC(); }
    BC f(B,C) { return BC(); }
    BA f(B,A) { return BA(); }
    CA f(C,A) { return CA(); }
    CB f(C,B) { return CB(); }

It defines three types A, B and C, and three functions that take
permuatations of A, B and C and return types that depend on the
arguments.

Now suppose I want to define a template function of two arguments that
uses the function f on those arguments.  It might look like

    template<class T1, class T2>
    g(T1 t1, T2 t2)
    {
      return f(t1,t2);
    }

Note that I haven't specified the return type of g.  As far as I know,
there is no mechanism in the C++ language to extract the return type of
f(T1,T2), so I can't figure out the return type g should have even
though it fully specified by the text of the program.

Now, I can certainly hack around this by introducing a parallel set of
trait classes to store the return types of f:

    template<class T1, class T2> class f_return {};
    template<> class f_return<A,B> { public: typedef AB type; };
    template<> class f_return<A,C> { public: typedef AC type; };
    template<> class f_return<B,C> { public: typedef BC type; };
    template<> class f_return<B,A> { public: typedef BA type; };
    template<> class f_return<C,A> { public: typedef CA type; };
    template<> class f_return<C,B> { public: typedef CB type; };

and then I can write g:

    template<class T1, class T2>
    f_return<T1,T2>::type g(T1 t1, T2 t2)
    {
      return f(t1,t2);
    }

There are a couple of problems with this:

1. A set of parallel classes like this is inherently error prone because
it repeats information.  Any change to the function(s) f requires a
change to the trait class f_return.

2. Separate libraries are unlikely to use the same notation for setting
up a trait class like this, making it impossible to rely on being able
to figure out the return type of classes that I don't control.  This
kills may forms of reuse.

3. Instead of writing functions for f I could write functors that you
could query about the return types.  This makes 1. less of a problem
because the specifications are in the same place, but 2. is still a
problem because separate libraries won't use the same notation.

It seems to me that this could be solved with an operator such as
'typeof' which would return the type of a function call or perhaps a
larger expression.  I would then be able to write g as:

    template<class T1, class T2>
    typeof(f(T1,T2)) g(T1 t1, T2 t2)
    {
      return f(t1,t2);
    }

or something like that.

I'm curious about a couple of things:

1. Is there some language feature that I've overlooked that would let me
do this sort of thing?  Note that I'm looking for a way to do it fully
at compile time, not using RTTI.  This is for heavily templated
applications.

2. Was a language feature like this discussed by the standards committee
and rejected?  If so, what were the reasons for its rejection?

--
Steve R. Karmesin
---
[ comp.std.c++ is moderated.  To submit articles: Try just posting with your
                newsreader.  If that fails, use mailto:std-c++@ncar.ucar.edu
  comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
  Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]