Topic: explicit cast (was C++0x)


Author: Sean Parent <sparent@Adobe.COM>
Date: Sat, 5 May 2001 12:14:47 GMT
Raw View
An earlier post got me thinking about about the need for "explicit" for cast
operators on classes. The normal recommendation of just using a member
function (such as "as()" isn't particularly helpful when you are trying to
plug the class into generic functions - but you don't want the cast to
happen implicitly.

I came up with the following solution:

//file: gen_explicit_cast.h

template <typename lht, typename rht>
inline lht explicit_cast(const rht& rhs)
    { return static_cast<lht>(rhs); }

//---

You can use this template function just as you would static_cast:

int foo = explicit_cast<double>(10);

But you can also specialize it for a particular class:

//--

class sample_t
    {
public:
    explicit sample_t(int x) : fX(x) { }

    friend double explicit_cast<double>(const sample_t& rhs);
private:
    int fX;
    };

template <>
inline double explicit_cast<double>(const sample_t& rhs)
    { return rhs.fX; }

//--

Now you can write a generic function that will work with this class (or a
similar class) or with anything for which a static cast is allowed. For
example, here is an alternate to std::accumulate.

//--

template <typename lht, class ForwardIterator>
lht sum(ForwardIterator first, ForwardIterator last)
    {
    lht result(0);
    while (first != last)
        {
        result += explicit_cast<lht>(*first);
        ++first;
        }
    return result;
    }

//--

Given the above you can write code like the following:

//--

sample_t samplea[] = { sample_t(1), sample_t(3), sample_t(5) };
std::cout << sum<double>(&samplea[0], &samplea[3]) << std::endl;

//--

You even get meaningful error messages (at least out of MWCW 6.1):


    sample_t sample(10);
    std::cout << explicit_cast<bool>(sample) << std::endl;

Will generate:

    Error   : illegal explicit conversion from 'const sample_t' to 'bool'

It would be a little spiffier if you could just specialize static_cast<>
then you wouldn't have to rewrite a bunch of existing generic algorithms.
But it seems to solve most of the issues. I've been giving some thought as
to how you would write a runtime_cast<> template that would behave like
dynamic_cast<> but you could specialize it for smart pointers. The
differences between behaviors for T& and T* is tripping me up along with
being able to specialize for any type which is, for example, derived from
auto_ptr<> - anyone want to take a stab at it?

--
Sean Parent
Sr. Engineering Manager
Adobe Workgroup Services
sparent@adobe.com


---
[ 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.research.att.com/~austern/csc/faq.html                ]





Author: jpotter@falcon.lhup.edu (John Potter)
Date: Sat, 5 May 2001 23:26:05 GMT
Raw View
On Sat,  5 May 2001 12:14:47 GMT, Sean Parent <sparent@Adobe.COM> wrote:

> An earlier post got me thinking about the need for "explicit" for cast
> operators on classes. The normal recommendation of just using a member
> function (such as "as()" isn't particularly helpful when you are trying to
> plug the class into generic functions - but you don't want the cast to
> happen implicitly.

I don't see any problem plugging the class into a well written generic
function.

[snip explicit_cast]

> But you can also specialize it for a particular class:
>
> //--
>
> class sample_t
>     {
> public:
>     explicit sample_t(int x) : fX(x) { }

      double as_double () const { return fX; }

>
>     friend double explicit_cast<double>(const sample_t& rhs);
> private:
>     int fX;
>     };
>
> template <>
> inline double explicit_cast<double>(const sample_t& rhs)
>     { return rhs.fX; }
>
> //--
>
> Now you can write a generic function that will work with this class (or a
> similar class) or with anything for which a static cast is allowed. For
> example, here is an alternate to std::accumulate.
>
> //--
>
> template <typename lht, class ForwardIterator>
> lht sum(ForwardIterator first, ForwardIterator last)
>     {
>     lht result(0);
>     while (first != last)
>         {
>         result += explicit_cast<lht>(*first);
>         ++first;
>         }
>     return result;
>     }
>
> //--
>
> Given the above you can write code like the following:
>
> //--
>
> sample_t samplea[] = { sample_t(1), sample_t(3), sample_t(5) };
> std::cout << sum<double>(&samplea[0], &samplea[3]) << std::endl;
>
> //--

struct Adder_sample_t {
   double operator() (double a, sample_t const& s) {
      return a + s.as_double();
      }
   };

cout << accumulate(samplea, samplea + 3, 0.0, Adder_sample_t()) << endl;

I don't see any improvement.  The standard algorithms are adaptable.
Would you suggest removing transform and adding explicit_cast to copy?
IMHO, this is just a special case substitution for the generality of
the standard algorithms.

John

---
[ 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.research.att.com/~austern/csc/faq.html                ]