给定一组类,使用匹配的方法参数调用该类

时间:2016-10-01 10:28:10

标签: c++ c++14

我有2个或更多的类继承自单个父级。它们都有重载的handle方法,但每个类的句柄方法都有不同的参数。

class CommandHandler {};

class FooCommandHandler : public CommandHandler
{
public:
  string handle(const FooCommand& c) { return c.getStringSomehow(); }
};

class BarCommandHandler : public CommandHandler
{
public:
  string handle(const BarCommand& c) { return c.getStringSomeOtherWay(); }
  string handle(const OtherBarCommand& c) { return c.youGetThePicture(); }
};

FooCommandHandler fooHandler;
BarCommandHandler barHandler;

我想要一个能够评估哪些类具有正确签名并调用它的函数。这可能吗?

理想情况下,这将在编译时完成,并且static_assert只有一个匹配。

鉴于签名template<typename C> string sendCommand(C c)

sendCommand<BarCommand>(c)会致电barHandler.handle(c)

sendCommand<FooCommand>(c)会致电fooHandler.handle(c)

1 个答案:

答案 0 :(得分:4)

常用功能重载适用于您的情况。你要签名template<typename C> string sendCommand(C c)所以模板参数是第一个函数参数的类型。然后定义:

string sendCommand(const FooCommand& c) {
    fooHandler.handle(c);
}
string sendCommand(const BarCommand& c) {
    barHandler.handle(c);
}

并打电话给他们。你甚至不需要模板。

如果你有很多命令和处理程序,你可以试试这个:

// We need a way to retrive handler by its type. Tuple is good for that.
std::tuple<FooCommandHandler, BarCommandHandler> handlers;

// Note the return type. If Handler on position handlerIndex does not have proper method, then instantiation will fail and, due to SFINAE, this function will just be ignored.
template<class Command, size_t handlerIndex = 0>
auto sendCommand(const Command& c) -> decltype(std::get<handlerIndex>(handlers).handle(c))
{
    return std::get<handlerIndex>(handlers).handle(c);
}

// Again, SFINAE technique. Compiler will stop search if the template above has been instantiated and will ignore this one. But in other case this template will be used and it will try to call next handler.
template<class Command, size_t handlerIndex>
std::string sendCommand(const Command& c)
{
    return sendCommand<Command, handlerIndex + 1>()(c);
}

请注意,您需要一种包含所有处理程序的注册表。这里我使用std :: tuple作为这样的注册表。