From: Paul Bibbings on
I'm wondering if there is any mileage in the idea of using template
parameter/arguments solely for the purpose of reducing the clutter of an
interface. To give a contrived example, suppose that I am modelling a
system that comprises a known collection of members of the system
and that I am only interested in how that system appears from a
particular point of view - for the sake of an example, let's use the
Solar System and it's nine planets. Say I'm wanting to model how it
appears from Earth.

Because it is possible to consider such a viewpoint as a facet of the
`system' itself, it may (or may not, but let's suppose so) seem
appropriate to avoid a first-thought model that comprises a SolarSystem
class that maintains a collection of nine descendents of class Planet.
(In this example, we could calculate appearances from tables of data
without the need for Planet objects with state, so we avoid them.)
However, I might then end up with a cluttered interface such as:

class SolarSystem {
// ...
public:
double get_distance_to_Mercury() const;
double get_distance_to_Venus() const;
double get_distance_to ...
// ...
};

and other such `noise'. As a result I might then start to think of
something like:

class Mercury; // incomplete
class Venus;
// ...

class SolarSystem {
// ...
public:
template<typename Planet>
double get_distance() const;
// ...
};

and then provide explicit specializations to do the individual look-ups
and calculations:

template<>
double SolarSystem::get_distance<Mercury>() const
{
// complicated, specific calculation here for Mercury
}

The user would then write:

double dist_to_Mars = solar_system::get_distance<Mars>();

The idea here is then to use what is effectively a set of deliberately
incomplete types to select specializations of a method, merely to
achieve a simplification of the interface; but where the template
arguments do not represent classes of objects in the model and have no
other function other than to permit this selection.

Is this a technique that is used at all in `real' code? I can't say
that I have necessarily come across it much, if ever, but it did seem to
fall naturally out of something I've been working on; although, on the
face of it, I can't help feeling that there is something unnatural about
it. It doesn't reduce code in any significant way, as there are still
eight explicit specializations to write, but the interface seems
cleaner. (Here I am assuming that there is no commonality between the
algorithms required for each specialization, as might very well be the
case in this example.)

Regards

Paul Bibbings

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

From: Hakusa on
On Mar 28, 8:35 pm, Paul Bibbings <paul.bibbi...(a)gmail.com> wrote:
> I'm wondering if there is any mileage in the idea of using template
> parameter/arguments solely for the purpose of reducing the clutter of an
> interface. To give a contrived example, suppose that I am modelling a
> system that comprises a known collection of members of the system
> and that I am only interested in how that system appears from a
> particular point of view - for the sake of an example, let's use the
> Solar System and it's nine planets. Say I'm wanting to model how it
> appears from Earth.

> class SolarSystem {
> // ...
> public:
> double get_distance_to_Mercury() const;
> double get_distance_to_Venus() const;
> double get_distance_to ...
> // ...
> };
>
> and other such `noise'. As a result I might then start to think of
> something like:
>
> class Mercury; // incomplete
> class Venus;
> // ...
>
> class SolarSystem {
> // ...
> public:
> template<typename Planet>
> double get_distance() const;
> // ...
> };
>
> and then provide explicit specializations to do the individual look-ups
> and calculations:
>
> template<>
> double SolarSystem::get_distance<Mercury>() const
> {
> // complicated, specific calculation here for Mercury
> }
>
> The user would then write:
>
> double dist_to_Mars = solar_system::get_distance<Mars>();

What problem does this solution solve?

SolarSystem system;
double x;

// Your original:
x = system.get_distance_to_Mercury();
// Changes to:
x = system.get_distance< Mercury >();

Is this really more convenient? It's not much easier to type, and
requires much more work on your side, having to define a partial type
as well as a template specialization for each one, and the user can
now type the fallowing code:

x = system.get_distance< int >();

But, seemingly any time an argument is of an integral type, known at
compile time, templates can be used to make the arguments compile
time. At the slight cost of readability since it's unusual.

PS: There are no longer nine main planets in the solar system. Pluto
was declared a dwarf planet, or something.


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

From: Jeffrey Schwab on
On 3/28/10 8:35 PM, Paul Bibbings wrote:

> I might then end up with a cluttered interface such as:
>
> class SolarSystem {
> // ...
> public:
> double get_distance_to_Mercury() const;
> double get_distance_to_Venus() const;
> double get_distance_to ...
> // ...
> };
>
> and other such `noise'. As a result I might then start to think of
> something like:

> class SolarSystem {
> // ...
> public:
> template<typename Planet>
> double get_distance() const;
> // ...
> };

> The user would then write:
>
> double dist_to_Mars = solar_system::get_distance<Mars>();

> Is this a technique that is used at all in `real' code?

Yes, all the time. It is not just for providing clean interfaces to human programmers, but also to enable template metaprogramming.

Suppose you have some other family of functions, e.g. gravity_from, that must call distance_to. If you've written the "cluttered" version, then you must write eight (screw Pluto) almost-identical gravity_from_planet .... functions. If instead you've
written the metaprogrammable version, then you can just write a single gravity_from<Planet> template that calls distance_to<planet>, and let the compiler dispatch to the right instantiation automatically. If you have many such sets of functions, this
kind of simple metaprogramming can avoid a lot of code duplication (thought it eventually does impact build time).

One quick word of advice: Just write a single function template to support nice syntax in the client code, then dispatch to either to a class template or to hand-written functions overloaded on a tag type. The rules for function template specialization
are not as flexible as those for class template specialization or function overloading.

Here's a small example. I'm going to disregard your "first thought" of a class hierarchy, because I don't understand why you want it, and I'm going to use mass instead of distance, because I can hard-code the planets' masses, whereas the distances vary
over time.

namespace planet {

enum planet_t {
mercury
, venus
, earth
, mars
, jupiter
, saturn
, uranus
, neptune
};

typedef double mass_t;

template<planet_t P>
struct tag
{ };

/* Mass in Kg, according to WikiAnswers. */
inline mass_t mass(tag< mercury >) { return 0.33e24; }
inline mass_t mass(tag< venus >) { return 4.87e24; }
inline mass_t mass(tag< earth >) { return 5.98e24; }
inline mass_t mass(tag< mars >) { return 0.65e24; }
inline mass_t mass(tag< jupiter >) { return 1900e24; }
inline mass_t mass(tag< saturn >) { return 570e24; }
inline mass_t mass(tag< uranus >) { return 87e24; }
inline mass_t mass(tag< neptune >) { return 100e24; }

template<planet_t P>
mass_t mass() {
return mass(tag<P>( ));
}
}

#include <iostream>

/* Doesn't this read nicely? "Mass of planet earth." If you wanted,
* you could even provide a set of suggested using-declarations in a
* public using.hh header.
*/
int main() {
using planet::mass;
std::cout << mass<planet::earth>() << std::endl;
}

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