"Transforming" 函数参数

"Transforming" Function Arguments

我正在编写与库交互的 C++ class。该库有一堆函数,如下所示:

Library.h

int FunctionA(int deviceNumber, ...);
int FunctionB(int deviceNumber, ...);
int FunctionC(int deviceNumber, ...);
int FunctionD(int deviceNumber, ...);
int FunctionE(int deviceNumber, ...);

我的 C++ class 的每个实例都有一个关联的 deviceNumber,它永远不会改变,所以我将 deviceNumber 存储为成员变量,每次调用库函数时,我将成员作为函数调用的第一个参数传入。

这很好,我没有真正的理由改变它的方式。但是出于好奇,我想知道 C++ 是否有任何 "transform" 参数的机制可以让我避免在每次调用中传递相同的参数。实现此目的的明显方法是使所有内容超载。假设我的 class 被称为 Foo:

Foo.cpp

int Foo::FunctionA(...) {
    // deviceNumber_ is a const member
    return ::FunctionA(deviceNumber_, ...);
}

唯一的问题是,这需要为每个函数调用一个方法,因此随着库的增长,如果没有代码生成器,它会变得越来越烦人。

有没有什么通用的方法可以在不实际重载函数的情况下提供重载行为? C++ 中是否有一种机制可以将一个参数 "expand" 转换为多个参数?我想象它看起来像:

// These two calls are equivalent
FunctionA(deviceNumber, ...);
FunctionA(Magic(...));
// Magic() expands the arguments, adding deviceNumber

即使解决方案比保留所有内容更丑陋且可读性更差,我也很好奇它是否可行。四处搜索后,可变参数模板似乎是最接近的匹配项,但我无法真正理解如何使用它们来完成此任务。

我放了伪代码,用于 C++ 类型结构。

Class原型可能是以下形式。

class Foo {
    private private_member_of_deviceNumber;
    ....
    int FunctionA(...);
    ....
}

Foo Class 构造函数会将 deviceNumber 赋值给私有成员变量。

class Foo::Foo(int deviceNumber) { 
    int private_member_of_deviceNumber = deviceNumber;
}

Foo Class 成员 FunctionA(...) 会喜欢这种形式。

int Foo::FunctionA(...) {
   return ::FunctionA( private_member_of_deviceNumber , ...);
}

这样怎么样?

我可能会在 cpp 文件中选择一个 marco 作为最简单的解决方案(尽管严格在 cpp 文件中)

可变参数模板在这里也有帮助。然而,听起来您正在做一些嵌入式的事情,这可能是个问题。

此外,我不确定您的意思是每个 FunctionA 都被重载了,还是 FunctionA 只引用了一个函数。

无论如何,如果有多个 FunctionAs,我的模板解决方案会有所帮助

template<typename... Args>
int Foo::FunctionA(Args&& ...args) {
    return ::FunctionA(deviceNumber_, std::forward<Args>(args)...);
}

您可能会对通用中继功能感到满意:

Live On Coliru

#include <iostream>

int    foo1(int device_number, const char*) { std::cout << __PRETTY_FUNCTION__ << "\n"; return device_number*42; }
double foo2(int device_number)              { std::cout << __PRETTY_FUNCTION__ << "\n"; return device_number*3.14159; }

struct facade {
    facade(int dn) : device_number(dn) {}

    template <typename F, typename... A>
        auto call(F&& f, A&&... args) const {
            return std::forward<F>(f)(device_number, std::forward<A>(args)...);
        }

  private:
    int device_number;
};

int main() {

    facade dev(2);

    std::cout << dev.call(foo1, "yes ma'am") << "\n";
    std::cout << dev.call(foo2) << "\n";

}