$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: [boost] An alternative approach to TypeErasure
From: Pyry Jahkola (pyry.jahkola_at_[hidden])
Date: 2012-06-24 06:34:13
Hi all,
I was quite impressed by Sean Parent's Friday talk in C++Now! 2012 (see 
slides in [1], code in [2]) and was left wondering whether the 
generation of his polymorphic object wrapper could be made simple 
somehow in C++11.
What I ended up with is tricking ADL into allowing the overloading of 
arbitrary (specifically crafted) function objects that I call 
_callables_, and then letting the user define interfaces by specifying 
sets of ("member") function signatures with a callable. You can find 
the code, and my rambling introductory README file, in GitHub:
    https://github.com/pyrtsa/poly
Comments are welcome!
* * *
Here's a somewhat shorter intro:
1) Create a callable F by simply deriving it from poly::callable<F>:
    struct draw_ : poly::callable<draw_> {};
    constexpr draw_ draw = {};
2) Or use the convenience macro POLY_CALLABLE(name) to do the same:
    POLY_CALLABLE(to_string); // type `to_string_` and object `to_string`
3) Overload your callables by overloading the function named `call`, 
with the callable as first argument:
    template <typename T>
    void call(draw_, T const & x, std::ostream & out, std::size_t position) {
        out << std::string(position, ' ') << x << std::endl;
    }
    std::string call(to_string_, int i) { return std::to_string(i); }
    template <typename T>
    std::string call(to_string_, std::vector<T> const & xs) {
        std::ostringstream s;
        s << '[';
        auto i = begin(xs), e = end(xs);
        if (i != e) s << *i++;
        while (i != e) s << ", " << *i++;
        s << ']';
        return s.str();
    }
Now you can call ::draw(x, o, p) and ::to_string(x) for several 
different types of x:
    ::draw(123, std::cout, 2); // prints "  123" to stdout
    ::to_string(std::vector<int>(1, 2, 3)); // "[1, 2, 3]"
But you can likewise extend ::draw and ::to_string further by 
overloading them for your own types too.
4) Define an interface by specifying the set of function signatures as 
template arguments to poly::interface:
    using drawable = poly::interface<
        void(draw_, poly::self const &, std::ostream &, std::size_t,
        std::string(to_string_, poly::self const &)>;
Now, the following calls got automatically defined, and forwarded to 
whatever type you successfully construct a `drawable` from:
    void call(draw_, drawable const &, std::ostream &, std::size_t);
    std::string call(to_string_, drawable const &);
* * *
I am aware that Steven Watanabe has put some astonishing work on his 
proposed Boost.TypeErasure. I'm open for discussion whether and how his 
or mine is a better approach, or if we could combine these into an 
eventual Boost.Interface library or such!
* * *
PS. Like I mention in my GitHub page, this kind of type erasure is 
common in functional languages like Haskell or Clojure. The problem 
they are solving there is known as the Expression Problem. IMO it makes 
very much sense to have the corresponding construct in C++ too, as 
we're moving towards a more and more functional style with parallelism 
and such.
Best Regards,
-- Pyry Jahkola pyry.jahkola_at_[hidden] https://twitter.com/pyrtsa