tags:

views:

88

answers:

4

I'm not sure this is possible, but is there a way, using template programming magic, to define a function that has different return values depending on what input it takes?

Potentially:

template<typename resultType>
resultType GetResult(const std::string &key); // where the value of key may change resultType

template<typename keyType, typename resultType>
resultType GetResult(keyType key);

Now, I know that the above isn't correct. To use the first one, you'd have to know what resultType was before calling the function. However, I've learned that a lot of "impossible" things are often made possible with just another layer (or two) of indirection. I just can't seem to find the right way to do it.

The second option tickles my brain though. I feel like I should be able to define some other helper object that maps strings to types (or whatever) and then the compile-time result of that will call GetResult with the appropriate template parameter.

Edit: Assume that the types used for resultType are unrelated. There is not an interface that can be tested for the "real" type (maybe it could be an int and a MyClass *).

Edit 2: The real-world usage is that I've got a third-party object that contains a collection of Widgets, Gadgets, etc. You can ask for these by string id (prefixed with a type, conveniently), but you have to parse the string to find out that you need to call "collectionInstance.getWidget(id)". My plan was to write a thin wrapper object that would intelligently know how to get at these internal objects.

+2  A: 

You need a helper metafunction that will map those types in your second example. typename helper<keyType>::type would then be your return type and the keyType template parameter would be removed. Your helper metafunction would need to create a type typedef depending on its template parameter. You may find boost::mpl::map a helpful utility for this task and possibly BOOST_STRONG_TYPEDEF to define different types based on std::string.

Noah Roberts
+2  A: 

No. You cannot make the return type, defined at compile-time, depend on a run-time value.

You could return a boost::variant or a boost::any, though.

Staffan
A: 

Based on your edit, what you want is not what you're asking for. What you need is:

1) A way to store a variable of any type among X,Y,Z unrelated types. 2) A way to parse your string to find out which function to call in order to get your variable.

The first can be solved with boost::variant.

The second can be solved by a two part solution. First is the parsing routine that returns a function or object that will actually make the appropriate call. The second is the set of objects or functions that make this call and assign to the variant. Thus you'd end up with something like so:

boost::variant<X,Y,Z> get_result(std::string stuff)
{
    return parser::instance().get_call(stuff).make_call(stuff);
}

If you actually need to separate the type information from the rest of the string then get_call will need to do that for you or you'll need another function that separates the string into two pieces that you then supply to the above calls.

Noah Roberts
I've updated the question in response to this answer. See Edit 2.
mos
I was hoping not to have to use boost::variant/QVariant/boost::any, which is why I was asking about how to change the result of my function based on runtime data. Oh well. I think you're probably right about this. I'm going to explore the option miked posted, but we'll see what happens with real-world usage.
mos
A: 

You can hack this with the cast operator. I make no claims about this being good programming practice, but it is doable:

    template <typename keyType>
    class GetResult
    {
      keyType mkey;

      GetResult(keyType key) : mkey(key) {}

      template <typename resultType>
      operator resultType()
      {
           //do stuff here that returns result type
      }
    }
miked
I can't possibly see how this should work. Which conversion operator is invoked depends on types involved in the expression it is used in (i.e. in <code>bool a = GetResult(key)</code> bool would mandate which conversion operator to use), resolved at compile-time, and not a run-time value such as a string.
Staffan