【问题标题】:Encapsulate a function with another function that has the same set of parameters用另一个具有相同参数集的函数封装一个函数
【发布时间】:2017-07-19 04:29:32
【问题描述】:

我有一个有很多参数的函数。 (4-7个参数)

为简单起见,这是一个例子:-

class B{
    friend class C;
    int f(int param1,float param2, structA a, structB b){
         //... some code ...
    }
    //.... other functions ....
};

有时,我想将它封装在另一个(更公开的)具有相同签名的函数下:-

class C{
    B* b;
    public: int g(int param1,float param2, structA a, structB b){
        return b->f(param1,param2,a,b);
    }
    //.... other functions ....
};

在我看来,上面的代码是:-

  • 乏味
  • 导致一些可维护性问题
  • 容易出现人为错误

是否有任何 C++ 技术/魔术/设计模式来帮助它?

在实际情况中,组合比继承更适合一点的情况大多发生在边缘情况下。

我觉得<...> 可能会解决我的问题,但它需要我想避免的模板。

【问题讨论】:

    标签: function c++11


    【解决方案1】:

    但它需要我想避免使用的模板。

    在我看来,这是错误的心态。如果你有充分的理由,你应该避免使用模板,否则你应该接受它们——它们是 C++ 语言的核心特性。

    使用可变参数模板,您可以创建一个完美转发包装器,如下所示:

    class C{
        B* b;
    public: 
    
        template <typename... Ts>
        int g(Ts&&... xs){
            return b->f(std::forward<Ts>(xs)...);
        }
    
    };
    

    上述g 函数模板 将接受任意数量的参数并通过完美转发它们调用b-&gt;f。

    (使用std::forward 允许您的包装器在调用包装器时正确保留传递的表达式的值类别。简而言之,这意味着不会进行不必要的复制/移动,并且引用将被正确传递因此。)

    【讨论】:

    • (悲伤的脸)使用模板,我无法将其移动到 .cpp -> 编译时间增加和其他不良副作用。
    • @javaLover:除非您的代码是大量模板化的并且充满了编译时元编程,否则添加一些包装器模板的影响将在编译时方面不明显。请澄清“其他不良副作用”。还要澄清“我无法控制我想公开哪个功能”。
    • 我无法控制要暴露哪个函数
    • 其他不好的副作用 = 循环依赖(问题不大)..... 有时候,我为 pimpl 封装,所以在这种情况下,一切都会丢失。 (对不起,我没有明确提及)
    • ...你真的需要 PImpl 吗?它has its own drawbacks。我可能错了,但对我来说,这听起来像是您不必要地努力避免使用模板和任何可能增加编译时间的东西。这可能是合理的,但是:您是否测量了添加模板对编译时间的影响? 如果没有,您应该这样做,然后得出您的结论。此外,PImpl 正在用运行时间换编译时间 - 如我链接的页面所示,存在一些开销。
    【解决方案2】:

    在公共标头中:

    using f_sig = int(int param1,float param2, structA a, structB b);
    
    class hidden;
    class famous {
      hidden* pImpl
    public:
      f_sig g;
    };
    

    在您的 .cpp 中:

    class hidden {
      friend class famous;
      f_sig f;
    };
    

    现在,您不能使用此模式定义f 或g 的功能,但这会声明它们的签名。如果您的定义与声明不匹配,则会出现错误。

    int hidden::f(int param1,float param2, structA a, structB b) {
      std::cout << "f!";
    }
    int famous::g(int param1,float param2, structA a, structB b) {
      return pImpl->f(param1, param2, a, b);
    }
    

    上面的签名输入错误,你会得到一个编译时错误。

    【讨论】:

    • 我以前从未见过这样的“使用”。这样可以节省大约 1/3 的重复,谢谢。
    • @javaLover 上面只是一个花哨的typedef。函数的 typedef 语法很尴尬,所以我使用using。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-14
    • 2019-09-23
    • 2018-07-28
    • 1970-01-01
    • 2023-03-27
    • 2013-05-23
    • 1970-01-01
    相关资源
    最近更新 更多