kfmfe04
kfmfe04

Reputation: 15327

How do I get tag dispatch to work with strings?

I need help getting the broken part of this code working.

How do I tag dispatch two functions (that return different value-types) based on a string?

If the overall code can be simplified with the intent of dispatching with strings, please do make recommendations. TY.

Requirements:

  1. Dispatch based on a string
  2. Rectangle overload needs to return int, while Circle overload needs to return std::string
  3. The mapping from Rectangle_Type to int and Circle_Type to std::string is fixed and known at compile time. Part of my problem is std::map is a run-time construct: I don't know how to make the std::string to tag mapping a compile-time construct.
  4. If necessary, run-time resolution is okay: however, the dispatch must allow for different return types based on the enum/type resolved to.

CODE

#include <map>
#include <string>
#include <iostream>

struct Shape    { };
struct Rectangle_Type : public Shape { using value_type=int;         };
struct Circle_Type    : public Shape { using value_type=std::string; };

Rectangle_Type Rectangle;
Circle_Type    Circle;

static std::map<std::string,Shape*> g_mapping =
{
    { "Rectangle", &Rectangle },
    { "Circle",    &Circle    }
};

int tag_dispatch( Rectangle_Type )
{
    return 42;
}

std::string tag_dispatch( Circle_Type )
{
    return "foo";
}

int
main()
{
    std::cerr << tag_dispatch( Circle    ) << std::endl;   // OK
    std::cerr << tag_dispatch( Rectangle ) << std::endl;   // OK

#define BROKEN
#ifdef BROKEN
    std::cerr << tag_dispatch( (*g_mapping["Rectangle"]) ) << std::endl;
    std::cerr << tag_dispatch( (*g_mapping["Circle"])    ) << std::endl;
#endif
}

Upvotes: 1

Views: 944

Answers (2)

cooky451
cooky451

Reputation: 3510

C++ does not have dynamic dispatch. This is probably what you expect to happen. You can emulate it with dynamic_cast, but that's slow and not recommended. You could use a virtual function returning an enum for the type though.

class base
{
public:
    virtual ~base() // Don't forget the virtual destructor if you want to inherit from it!
    {}

    enum type
    {
        a, 
        b, 
    };

    virtual type get_type() const = 0;
};

class a : public base
{
public:
    virtual type get_type()
    {
        return base::type::a;
    }
};

class b : public base
{
public:
    virtual type get_type()
    {
        return base::type::b;
    }
};

Upvotes: 0

Karthik T
Karthik T

Reputation: 31952

Unless C++11 has changed this.. The problem is that you are dereferencing a Shape* pointer, which means the resulting datatype (Shape&) does not have a valid overload of tag_dispatch.

You can do something like g_mapping["Rectangle"]->tag_dispatch(). Or more cleanly rewrite as below.

std::string tag_dispatch( Shape& shape)
{
    return shape->tag_dispatch();
}

This way you can support non Shape objects with an identical interface. Both need you to make tag_dispatch as a virtual function of Shape as well.

Upvotes: 1

Related Questions