Как избежать дублирования кода при перегрузке функций

#c #c 11 #overloading

Вопрос:

У меня есть пара перегруженных функций:

 void func(const std::stringamp; str, int a, char ch, double d) {
    // piece of code A
    sendMsg(str, a, ch, d);
    // piece of code B
}

void func(int a, char ch, double d) {
    // piece of code A
    sendMsg(a, ch, d);
    // piece of code B
}
 

piece of code A и piece of code B являются точно такими же, разница только в параметре sendMsg .

Есть ли какой-то способ избежать дублирования кода?

Комментарии:

1. Как выглядит sendMsg?

2. @mfnx Это не имеет значения, нет? sendMsg это библиотечная функция, которая выполняет некоторую работу с сокетами. Я все равно не могу это изменить.

3. Я не понял вопроса. Почему мы не можем переместить A и B в его собственные функции? Кто-нибудь, пожалуйста, объясните.

4. @Yves вот в чем проблема с вопросом, как избежать кода, не показывая код 😉 Не беспокойтесь, я думаю, что это общая трудность с такого рода вопросами

5. Вопрос IMO лишен важных деталей. Эти ответы на ответы not suitable for my case являются лучшим доказательством этого.

Ответ №1:

шаблон может быть возможностью:

 template <typename ... Ts>
auto func(const Tsamp;... args)
-> decltype(sendMsg(args...), void()) // SFINAE to only allow correct arguments
{
    // piece of code A
    sendMsg(args...);
    // piece of code B
}
 

но движение // piece of code A по своей собственной функции, вероятно, было бы моим выбором.

Ответ №2:

Вам пришлось бы сделать что-то вроде

 void codeA() {
    // ...
}

void codeB() {
    // ...
}

void func(const std::stringamp; str, int a, char ch, double d) {
    codeA();
    sendMsg(str, a, ch, d);
    codeB();
}

void func(int a, char ch, double d) {
    codeA();
    sendMsg(a, ch, d);
    codeB();
}
 

Комментарии:

1. Ну, добавьте две функции, которые не подходят для моего случая.

Ответ №3:

Другая идея состояла бы в том, чтобы присвоить значение по умолчанию str :

 void func(int a, char ch, double d, const std::stringamp; str = "")
{
    // piece of code A
    if (str.empty()) sendMsg(a, ch, d);
    else sendMsg(str, a, ch, d);
    // piece of code B
}
 

Комментарии:

1. это может быть const std::stringamp; также по умолчанию.

2. также это будет препятствовать вызову sendMsg(str,a,ch,d) , когда str == "" (но не по умолчанию). Вот почему я предлагаю использовать std::optional вместо этого (хотя мы не знаем, что sendMsg это такое, это может не иметь значения)

3. @463035818_is_not_a_number Да, конечно… Я это исправлю.

Ответ №4:

Конечно, используйте функтор:

 template <typename F> void func2(Famp;amp; f) {
    // piece of code A
    f();
    // piece of code B
}
 

Использование:

 void func(int a, char ch, double d) {
    func2([amp;](){ sendMsg(a, ch, d); });
}
 

Небольшое объяснение: Принятый в настоящее время ответ полностью подходит, когда вам нужно вызвать один и тот же код с разными параметрами. Но когда вам нужно «внедрить» произвольный код (возможно, несколько фрагментов произвольного кода) в другую функцию, передача временной лямбды-ваш лучший выбор. Концептуально, то, что приемная функция видит/получает, — это какой-то абстрактный «вызываемый» объект (на самом деле, это может быть что угодно с operator () , а не только лямбда), который он вызывает в свое время. И поскольку это шаблонная функция, она будет скомпилирована в код с нулевыми накладными расходами, «как если бы» фактический код был скопирован туда. Часть использования просто показывает синтаксис c для создания вызываемого объекта с произвольным кодом на месте (я советую прочитать ссылки на языки/учебные пособия по лямбдам, чтобы лучше понять внутреннее устройство).

Комментарии:

1. Конечно, пожалуйста, не стесняйтесь задавать вопросы.

2. О, я понял. Хорошее решение~

3. Единственная проблема заключается в том, что мы не знаем, должна ли ОПЕРАЦИЯ использовать входные данные для большего, чем просто вызов sendMsg . Это связано с вопросом, а не с решением здесь.