C ++中的可变参数函数是否支持命名字段?

时间:2018-05-31 18:00:20

标签: c++ c++11 variadic-templates variadic-functions

我正在实现一个名为“Signal<args>”的可变函数仿函数,它管理匹配函数签名类型的仿函数的内部队列。在调用Signal<args>::operator()时,队列中的每个仿函数都使用相同的输入参数执行。这个想法是它是一个纯C ++ 11对象类型,它重现了与Qt的Signal / Slot构造相同的一些设计行为,但静态编译时具有最小的依赖性。我有一切工作,但我想提高这种通用的可读性。

语法我有:

Signal<int, double> signal;
signal.add(BLOCK, [](int EmployeeID, double FavoriteNumber) {
    std::cout << EmployeeNames[EmployeeID]
              << " has favorite number of "
              << FavoriteNumber << std::endl;
});
signal.add(BLOCK, [](int EmployeeID, double FavoriteNumber) {
    if (EmployeeID > FavoriteNumber) {
        std::cout << EmployeeNames[EmployeeID]
                  << " has ID bigger than favorite number.\n";
    }
});
signal(5, 3.1415); //execute both functors with args = (5, 3.1415)

我想拥有什么:

Signal<int EmployeeID, double FavoriteNumber> signal;
signal.add(BLOCK, [](int EmployeeID, double FavoriteNumber) {
    std::cout << EmployeeNames[EmployeeID]
              << " has favorite number of "
              << FavoriteNumber << std::endl;
});
signal.add(BLOCK, [](int EmployeeID, double FavoriteNumber) {
    if (EmployeeID > FavoriteNumber) {
        std::cout << EmployeeNames[EmployeeID]
                  << " has ID bigger than favorite number.\n";
    }
});
signal(5, 3.1415); //execute both functors with args = (5, 3.1415)

唯一的区别是我希望模板化信号类型的声明为了可读性而指定参数的名称。理想情况下,我希望这些名称是强制性的,如果未指定则无法编译。

有没有办法实现这个目标?

2 个答案:

答案 0 :(得分:2)

您可以利用函数类型允许其参数名称的事实,让您编写:

Signal<void(int EmployeeID, double FavoriteNumber)> mySignal;

该名称不是强制性的,但允许使用。

为此,请对Signal

进行部分专业化
template <typename>
class Signal;

template <typename... Args>
class Signal<void(Args...)> {
    // Old implementation of Signal<...>
};

答案 1 :(得分:2)

简单的解决方案是使用标签类型,例如

struct EmployeeID_T {};
struct FavoriteNumber_T {};

并将参数类型绑定到名称,例如

using EmployeeID = SignalArg<EmployeeID_T, int>;
using FavoriteNumber = SignalArg<FavoriteNumber_T, double>

所以你得到了

Signal<EmployeeID, FavoriteNumber> mySignal;
signal.add(BLOCK, [](EmployeeID eid, FavoriteNumber fn) {
    std::cout << EmployeeNames[eid]
              << " has favorite number of "
              << fn << std::endl;
});
signal.add(BLOCK, [](EmployeeID eid, FavoriteNumber fn) {
    if (eid > fn) {
        std::cout << EmployeeNames[eid]
                  << " has ID bigger than favorite number.\n";
    }
});
mySignal(5, 3.1415); //execute both functors with args = (5, 3.1415)

你需要一个带有适当构造函数和转换运算符的SignalArg模板,但由于我没有写出来,可能需要一些强制。

标记类型阻止具有相同基础类型的不同参数之间的隐式转换,这只是使用typedef允许的。

你也可以通过使SignalArg转换构造函数显式来获得类似命名的参数,因此调用看起来像

mySignal(EmployeeID{5}, FavoriteNumber{3.1415});