在C ++中传递多个函数参数的最佳实践

时间:2017-10-04 13:40:48

标签: c++ templates lambda generic-programming

我想知道在C ++中传递多个函数参数的最佳实践是什么。我想遵循STL中所见的正确的通用设计原则。

我有一个通用的算法功能。使用模板,它允许客户端选择将用于运行算法的数据结构以及从中提取数据的容器实现。但是,为了使其可以重复使用,我选择了许多应插入客户端设计代码的地方。

template<class CustomContainerIterator, class Queue, class Element>
void run_generic_algorithm(CustomContainerIterator container,
                           std::function<void(Element)> client_code1,
                           std::function<void(Element)> client_code2,
                           std::function<void(Element)> client_code3)
{
    Queue queue;
    //Push things iterated through onto the queue
    Element queue_element = queue.top();
    client_code1(queue_element);
    // Run code modifying queue
    client_code2(queue_element);  
    // Run code modifying queue
    client_code3(queue_element);    
}

client_code()函数由客户端指定,可以修改客户端拥有的相同变量。在我的代码中,有5个客户端函数。我最初将它们全部作为lambda表达式传递并捕获了我想要修改的客户端变量。但是,这使得函数调用非常详细。

大多数时候我甚至没有指定所有的客户端函数,所以我必须放入一个什么都不做的lambda函数。有没有更好的方法,实现我想要的。我想坚持正确的通用编程原则?

好的,所以我已经阅读了答案。我能结合这样的想法吗?现在我认为我不需要虚函数。

template <typename Element>
struct Customization {
    void client_code1(Element) {}
    void client_code2(Element) {}
    void client_code3(Element) {}
    void client_code4(Foo) {}
    void client_code5(Bar) {}
};

template <typename Element>
struct Implementation : public Customization {
    Data some_data;
    void client_code2(Element) {
        //Fill some_data with information.
    }
};

template<class Queue, class CustomContainerIterator, class CustomImplementation>
void run_generic_algorithm(CustomContainerIterator container,
                           CustomImplementation implementation)
{
    Queue queue;
    //Push things iterated through onto the queue
    auto queue_element = queue.top();

    implementation.client_code1(queue_element);
    // Run code modifying queue
    implementation.client_code2(queue_element);  
    // Run code modifying queue
    implementation.client_code3(queue_element);    
}

使用

std::vector<int> v;
Implementation <int> custom;
run_generic_algorithm<std::queue<int>>(v, custom);

2 个答案:

答案 0 :(得分:2)

  

有5个客户端功能。

您可以改为通过结构

template <typename Element>
struct Customization {
    std::function<void(Element)> client_code1;
    std::function<void(Element)> client_code2;
    std::function<void(Element)> client_code3;
    std::function<void(Foo)> client_code4;
    std::function<void(Bar)> client_code5;
};

甚至可能是界面:

template <typename Element>
struct Customization {
    virtual ~Customization() = default;
    virtual void client_code1(Element) = 0;
    virtual void client_code2(Element) = 0;
    virtual void client_code3(Element) = 0;
    virtual void client_code4(Foo) = 0;
    virtual void client_code5(Bar) = 0;
};

然后

template<class Range, class Element>
void run_generic_algorithm(Range& r, const Customization <Element>& customization);
  

大多数时候我甚至没有指定所有的客户端函数,所以我必须放入一个什么都不做的lambda函数。

使用之前的评论,您可以为以前结构的成员提供默认值。

否则,您可以为参数添加默认值或创建重载。

答案 1 :(得分:1)

在与您描述的类似情况下,我将客户端函数放入类/结构中,并将该类作为模板参数或实例传递。 (如果函数在泛型函数外部具有共享状态,则只需要传递一个类对象。)

我发现将函数放在一个类中也可以更容易地记录函数在泛型函数中的作用。

template< class Queue >
class a_traits{
public:
   static void client_code1( Queue & );
   static void client_code2();
   static void client_code3();

};
template <class Container, class Queue, class Traits>
void run_generic_algorithm(const Container& container) {
  Queue queue;
  Traits::client_code1(queue_element);
  // Run code modifying queue
  Traits::client_code2();  
  // Run code modifying queue
  Traits::client_code3();    
}