0

I wrote a C++ template class, but I do not have the type to instantiate the class. Types are stored in a string format. So I have to do something like this:

if ( propType == "char") {
   Property<char> pChar = ...
} else if ( propType == "int") {
   Property<int> pChar = ...
} if ( propType == "double") {
   Property<double> pChar = ...
} 

I am not liking this if-else- loop, is there any way to avoid this, or any other solution to such problem?

3
  • 1
    How do you use pChar after the initalization? Commented Nov 10, 2012 at 17:20
  • 4
    Not possible this way, and not desirable. You want a dynamic language for this kind of stuff. Commented Nov 10, 2012 at 17:22
  • 2
    You have to use if statements in such a way that they'll always be true? Commented Nov 10, 2012 at 17:27

2 Answers 2

4

Many ways, but it's impossible to choose a good one without knowing how you use it in your particular case.

As a demonstration:

  • Let us suppose that all Property<T> classes inherit from PropertyBase
  • Let us suppose that you initialize them by parsing the type from a string

Here is some code then:

using PropertyPtr = std::unique_ptr<PropertyBase>;
using Parser = std::function<PropertyPtr(std::string const&, std::string const&)>;

template <typename T>
PropertyPtr parse(std::string const& type, std::string const& value) {
    T v = boost::lexical_cast<T>(value);
    return PropertyPtr(new Property<T>(std::move(v)));
}

std::map<std::string, Parser> const parsers = {
    std::make_pair("char", parse<char>),
    std::make_pair("int", parse<int>),
    std::make_pair("double", parse<double>)
};

void dummy(std::string const& type, std::string const& value) {
    auto const it = parsers.find(type);
    assert(it == parsers.end() && "No parser");

    auto const& parser = it->second;
    PropertyPtr property = parser(type, value);

    // do something with property
}

Hope this helps.

Sign up to request clarification or add additional context in comments.

Comments

1

There are a couple of considerations here.

Suppose you want to parse the file from disk, then based off of the type on disk you want to create an object. You handle these objects in a mostly indistinguishable way. There are a finite list of types you are working with.

The answer I'd use for this would be a boost::variant to store the data, and a map (like Matthiew's answer) that maps the name of the type to a reader (or parser) for the type. The reader then returns a boost::variant<int, double, char, string, etc>.

Code then interacts with the variant in a pseudo uniform way. Helper functions use boost functions to call functors to interact with the variant.

Ie, something like this:

typedef boost::variant<int, double> myVariant;
typedef std::function< myVariant( input_stream_type& ) > ValueParser;
ValueParser GetParser( std::string typename );
// ...
struct DoTypeSpecificWork
{
  typedef void result_type;
  void operator()( int ) { /* ... int code goes here */ }
  void operator()( double ) { /* ... double code goes here */ }
};
ValueParser parser = GetParser( propType );
myVariant var = parser( input_stream );
boost::variant::apply_visitor( DoTypeSpecificWork(), var );

Another option is to have a base PropertyBase class that has abstract interfaces that are type agnostic. Then Property<T> child classes that implement those abstract interfaces for each type. Creating those Property<T> child classes could be done directly (forcing the parser to know about your Property class), or indirectly (ie, you take a variant and produce an appropriate Property<T>, which decouples to parsing code from your type abstraction).

Basically, you need to decide between type erasure, type abstraction and template based programming to deal with multiple types. They all have their own advantages.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.