[ create a new paste ] login | about

Link: http://codepad.org/CYmgggw5    [ raw code | output | fork ]

C++, pasted on Oct 19:
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_base_of.hpp>


namespace fruit
{


struct apple
{
    typedef void sourness;

    std::string name;
    apple(std::string const& n) : name(n) {}
};

struct pear
{
    typedef void juiciness;

    std::string other_name;
    pear(std::string const& n) : other_name(n) {}
};


struct orange
{
    std::string name;
    orange(std::string const& n) : name(n) {}
};

struct lime
{
    std::string name;
    lime(std::string const& n) : name(n) {}
};

struct banana
{
    std::string name;
    banana(std::string const& n) : name(n) {}
};


struct citrus_tag {};
struct pome_tag {};

struct apple_tag : pome_tag {};
struct pear_tag : pome_tag {};

struct banana_tag {};

struct orange_tag : citrus_tag {};
struct lemon_tag : citrus_tag  {};
struct lime_tag : citrus_tag  {};



// Attach tags:
template <typename T> struct tag {};
template <> struct tag<apple> { typedef apple_tag type; };
template <> struct tag<pear> { typedef pear_tag type; };
template <> struct tag<orange> { typedef orange_tag type; };
template <> struct tag<lime> { typedef lime_tag type; };
template <> struct tag<banana> { typedef banana_tag type; };



//First version, without list:
/*
template <typename Tag, typename BaseTag> 
struct tag_cast
{ 
    typedef typename boost::mpl::if_
        <
            typename boost::is_derived<Tag, BaseTag>::type,
            BaseTag,
            Tag
        >::type type;
};
*/



// tag_cast: downcasts a tag to a specified base-tag, 
// or to the first encountered in a list
template 
<
    typename Tag, typename BaseTag = void, 
    typename BT2 = void, typename BT3 = void, typename BT4 = void,
    typename BT5 = void, typename BT6 = void, typename BT7 = void
> 
struct tag_cast
{ 
    typedef typename boost::mpl::if_
        <
            typename boost::is_base_of<BaseTag, Tag>::type,
            BaseTag,
            // Try next one in line:
            typename tag_cast<Tag, BT2, BT3, BT4, BT5, BT6, BT7, void>::type
        >::type type;
};

template <typename Tag> 
struct tag_cast<Tag, void, void, void, void, void, void, void>
{ 
    // If not found, take specified tag, so do not cast
    typedef Tag type;
};



namespace dispatch 
{

template <typename T> struct has_vesicles : boost::false_type {}; 
template <> struct has_vesicles<citrus_tag> : boost::true_type {};


template <typename T> struct species
{
    static std::string apply() { return "unknown"; }
};

template <> struct species<citrus_tag> 
{
    static std::string apply() { return "citrus"; }
};

template <> struct species<pome_tag> 
{
    static std::string apply() { return "pome"; }
};


template <typename T>
struct eat {};

template <> struct eat<apple_tag>
{
    static void apply(apple const& a)
    {
        std::cout << "apple: " << a.name << std::endl;
    }
};

template <> struct eat<pear_tag>
{
    static void apply(pear const& p)
    {
        std::cout << "pear: " << p.other_name << std::endl;
    }
};



} // ns dispatch


// Generic functions
template <typename Fruit>
void eat(Fruit const& fruit)
{
    dispatch::eat<typename tag<Fruit>::type>::apply(fruit);
}

template <typename Fruit>
std::string has_vesicles(Fruit const& fruit)
{
    // (Potentially) go up in hierachy: take tag corresponding to Fruit, 
    // downcast to citrus_tag if possible
    typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag>::type tag;

    return std::string("has vesicles: ") 
        + (dispatch::has_vesicles<tag>::value ? "true" : "false");
}

template <typename Fruit>
std::string species(Fruit const& fruit)
{
    typedef typename tag_cast<typename tag<Fruit>::type, citrus_tag, pome_tag>::type tag;

    return std::string("species: ") + dispatch::species<tag>::apply();
}


} // ns fruit




int main()
{
    using namespace fruit;

    apple a("my apple");
    pear p("my pear");
    eat(a);
    eat(p);

    orange o("my orange");

    std::cout << has_vesicles(a) << std::endl;
    std::cout << has_vesicles(p) << std::endl;
    std::cout << has_vesicles(o) << std::endl;

    banana b("my banana");


    std::cout << species(a) << std::endl;
    std::cout << species(p) << std::endl;
    std::cout << species(o) << std::endl;
    std::cout << species(b) << std::endl;

    return 0;
}


Output:
1
2
3
4
5
6
7
8
9
apple: my apple
pear: my pear
has vesicles: false
has vesicles: false
has vesicles: true
species: pome
species: pome
species: citrus
species: unknown


Create a new paste based on this one


Comments: