Adding a template parameter to API struct and maintaining backwards compatibility with partial specialization

StackOverflow https://stackoverflow.com/questions/17178195

Question

I have a software component with an API I maintain with clients. Below is a simplification of my problem.

This is part of the interface:

typedef unsigned int CustomerId;
template <typename DataType>
struct CommandResult
{
    std::map<CustomerId, DataType> data;
};

And in the API there's a long list of API methods such as this:

APIResult APIMethod(input_parameters, CommandResult<SomeType>& output);

Now I'm adding a few new API methods, which require a slightly different CommandResult. So we'll call it GeneralCaseCommandResult:

template <typename ID, typename DataType>
class GeneralCaseCommandResult 
{
    std::map<ID, DataType> data;
};

It's very useful to me to keep both CommandResult types in the same struct because I reuse a lot of code internally by using templates.

However, I don't want to force my clients to change a lot of code just to replace CommandResult, so I did this:

template <typename DataType>
class CommandResult : public GeneralCaseCommandResult<CustomerId, DataType> {};

and everything's peachy.

Now I want to call my API methods from within some of my templated functions, like this:

template <typename ID, typename DataType>
void MyInternalFunc()
{
    GeneralCaseCommandResult<ID, DataType> output;

    // Will not compile
    APIResult res = APIMethod(params, output);

    ...
}

This of course will not work since the existing API methods receive CommandResult, and not its base class.

I tried creating a traits class per ID/DataType to hold the CommandResult type, and specialize it on CustomerId to support CommandResult. However it doesn't work since the other ID's are also typedefs of unsigned int (I use them to maintain order and readability in my code and API).

I also found Q&A here that I can't specialize on two typedefs which are actually the same type, and since these are just numeric ID's I don't want to use structs instead of int.

Any ideas how I can call my APIMethod from within the templated function while keeping all the above requirements?

Was it helpful?

Solution

The easiest solution might be default template parameters, if that works for you:

typedef unsigned int CustomerId;
template <typename DataType, typename ID = CustomerId>
struct CommandResult
{
    std::map<ID, DataType> data;
};

If that doesn't do the trick my next suggestion would be to use BOOST_STRONG_TYPEDEF to create all the id types that aren't CustomerId, causing each one to be a distinct type you can create traits for.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top