【问题标题】:"Transforming" Function Arguments“转换”函数参数
【发布时间】:2015-05-08 16:47:33
【问题描述】:

我正在编写与库接口的 C++ 类。该库有一堆函数,如下所示:

图书馆.h

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

我的 C++ 类的每个实例都有一个永远不会改变的关联 deviceNumber,因此我将 deviceNumber 存储为成员变量,每次调用库函数时,我都会将该成员作为函数调用的第一个传入争论。

这很好,我没有真正的理由改变它的方式。但出于好奇,我想知道 C++ 是否有任何机制来“转换”参数,让我避免在每次调用中传递相同的参数。实现这一点的明显方法是重载所有内容。假设我的班级名为Foo

Foo.cpp

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

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

是否有任何通用的方法来提供重载行为而不实际重载函数? C++ 中是否有一种机制可以将一个参数“扩展”为多个参数?我想象它会是这样的:

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

即使解决方案比不理会所有内容更丑陋且可读性差,但我很好奇它是否可能。在四处搜索之后,可变参数模板似乎是最接近的匹配项,但我无法真正理解如何使用它们来实现这一点。

【问题讨论】:

  • 如何将 deviceNumber 设为私有值。并制作基类。那么继承的成员函数就不需要使用devicenumber了。
  • 宏能工作吗? #define MAGIC(...) deviceNumber_, __VA_ARGS__
  • 宏也是不错的选择,差别很小
  • @cpplover-SlwEssencial - 你能举个例子说明一下吗?难道我还不需要手动重载每个库调用吗?
  • @KerrekSB - 哇,我完全不知道可变参数宏是一回事。该宏似乎运行良好。我将不理会所有事情,因为我无法将任何预处理器魔法偷偷带入代码中,但这绝对是一个很酷的解决方案。谢谢。

标签: c++ c++11 arguments


【解决方案1】:

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

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";

}

【讨论】:

  • if Bjarne gets his way,我们可以将后者拼写为foo1(dev, "yes ma'am"),这样看起来统一又方便:-) 或者我们采用N4165,OP 可以说deviceNumber.functionA(...)...令人难以置信。
  • 哦..模板参考的好用法。感谢您以这种方式展示。但非常复杂和困难。 ^^
【解决方案2】:

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

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

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

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

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

【讨论】:

  • 可变参数模板不是问题。该库控制嵌入式设备,但我从具有完整 C++11 支持的桌面程序调用该库。此外, FunctionA 没有重载。我将使用等效方法包装全局 FunctionA 调用的解决方案称为“重载”,但我不确定这是否是正确的表述方式。
【解决方案3】:

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

类原型可能有以下形式。

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

Foo 类构造函数会将 deviceNumber 分配给私有成员变量。

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

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

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

这样怎么样?

【讨论】:

  • 这就是我试图用我的Foo.cpp 示例来解决的问题。这行得通,但是如果库有一堆具有相似原型的函数,我最终会定义大量方法来重载它们。我想知道是否有办法在固定开销的情况下做到这一点,不管有多少库函数。
  • @Matt 基本形式是这种方式,您需要删除同样耗时的工作复制和粘贴一堆库代码。然后,您使用宏和模板,其他答案发布。干得好!
猜你喜欢
  • 1970-01-01
  • 2015-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-04
  • 1970-01-01
  • 2019-04-13
  • 2013-07-11
相关资源
最近更新 更多