将模板参数添加到API结构并保持与部分特化的向后兼容性

时间:2013-06-18 20:22:17

标签: c++ templates backwards-compatibility

我有一个软件组件,其中包含我与客户一起维护的API。 以下是我的问题的简化。

这是界面的一部分:

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

在API中有很多API方法,例如:

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

现在我添加了一些新的API方法,这些方法需要稍微不同的CommandResult。所以我们称之为GeneralCaseCommandResult:

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

将两个CommandResult类型保存在同一个结构中对我来说非常有用,因为我通过使用模板在内部重用了很多代码。

但是,我不想强​​迫我的客户更改大量代码只是为了替换CommandResult,所以我这样做了:

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

一切都很好。

现在我想从我的一些模板化函数中调用我的API方法,如下所示:

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

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

    ...
}

这当然不会起作用,因为现有的API方法接收CommandResult,而不是它的基类。

我尝试为每个ID / DataType创建一个traits类来保存CommandResult类型,并在CustomerId上专门设置它以支持CommandResult。但是它不起作用,因为其他ID也是unsigned int的typedef (我使用它们来维护我的代码和API中的顺序和可读性)。

我在这里也发现Q&amp; A我不能专注于两个实际上是同一类型的typedef,因为这些只是数字ID,我不想使用结构而不是int。

如何在保留所有上述要求的同时从模板化函数中调用我的APIMethod的任何想法?

1 个答案:

答案 0 :(得分:1)

最简单的解决方案可能是默认模板参数,如果适用于您:

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

如果不能解决这个问题,我的下一个建议是使用BOOST_STRONG_TYPEDEF来创建非CustomerId的所有id类型,从而使每个类型成为可以为其创建特征的不同类型。 / p>