Arhn - архитектура программирования

Функция Variadic без указанного первого параметра?

Из любопытства я решил попробовать написать базовый класс C++, который имитирует шаблон множественного делегата C#. Приведенный ниже код в основном выполняет свою работу, с неприятной жертвой потери почти всей безопасности типов, но необходимость использовать начальный фиктивный параметр для настройки va_list действительно кажется немного странной. Есть ли способ использовать va_list без этого? Я понимаю, что есть способы сделать это (например) с помощью boost, но я стремился к чему-то очень простому, что использовало бы только стандартную библиотеку.

#include <vector>
#include <iostream>
#include <string>
#include <stdarg.h>
#include <algorithm>

using namespace std;

class CDelegate
{
public:
 virtual bool operator()(va_list params) = 0;
};

class CMultipleDelegateCaller
{
public:
 typedef vector<CDelegate*> CDelegateVector;

 CMultipleDelegateCaller& operator+=(CDelegate &rDelegate)
 {
  m_apDelegates.push_back(&rDelegate);
  return (*this);
 }

 CMultipleDelegateCaller& operator-=(CDelegate &rDelegate)
 {
  CDelegateVector::iterator iter = 
   find(m_apDelegates.begin(), m_apDelegates.end(), &rDelegate);
   if (m_apDelegates.end() != iter) m_apDelegates.erase(iter);
  return (*this);
 }

 bool Call(int iDummy, ...)
 {
  va_list params;
  CDelegate* pDelegate;
  CDelegateVector::iterator iter;
  for (iter = m_apDelegates.begin(); iter != m_apDelegates.end(); ++iter)
  {
   pDelegate = *iter;
   va_start(params, iDummy);
   if (!(*pDelegate)(params)) return false;
   va_end(params);
  }
  return true;
 }

private:
 CDelegateVector m_apDelegates;
};

class CTestDelegate:
 public CDelegate
{
public:
 CTestDelegate():m_iId(++s_iCount) {}
 virtual bool operator()(va_list params)
 {
  int iIntParam = va_arg(params, int);
    char* szCharPtrParam = va_arg(params, char*);
   string* psStringParam = va_arg(params, string*);
  cout<<m_iId<<"{"
   <<iIntParam<<", "
   <<szCharPtrParam<<", "
   <<*psStringParam<<"}"<<endl;

  return true;
 }
 int m_iId;
 static int s_iCount;
};
int CTestDelegate::s_iCount = 0;

int main(int argc, char* argv[])
{
 CMultipleDelegateCaller cDelegateCaller;
 CTestDelegate cTestDelegate1;
 CTestDelegate cTestDelegate2;

 cout<<"--------------------"<<endl;
 cDelegateCaller += cTestDelegate1;
 cDelegateCaller += cTestDelegate2;
 string sString("World");
 cDelegateCaller.Call(1, 2, "Hello", &sString);
 cout<<"--------------------"<<endl;
 cDelegateCaller -= cTestDelegate1;
 cDelegateCaller.Call(1, 2, "Hello", &sString);
 cout<<"--------------------"<<endl;
 cDelegateCaller -= cTestDelegate2;
 cDelegateCaller.Call(1, 2, "Hello", &sString);
 cout<<"--------------------"<<endl;

 cin>>sString;
 return 0;
}
17.09.2009

Ответы:


1

Функции с многоточием в C++ предназначены только для совместимости с C. Используя C++, я бы вернул временный вспомогательный объект в функцию Call и добавил шаблон operator% для передачи переменного количества аргументов. Чтобы использовать его следующим образом:

cDelegateCaller.Call() % 2 % "Hello" % sString; // dummy argument isn't required

Что касается вашего вопроса, стандарт требует вызывать va_start перед любым доступом к безымянным аргументам. И va_start требует второго аргумента, который является идентификатором самого правого параметра в списке переменных параметров в определении функции.

17.09.2009
  • Как это будет использоваться для вызова функции? Вызов будет выполняться перед каждым из операторов модуля, поэтому параметры еще не будут переданы. 17.09.2009
  • Фактическое действие будет происходить в деструкторе временного объекта, который вернет функция Call. Вы можете найти образец здесь - stackoverflow.com/questions/1394053/ 17.09.2009
  • Итак, ссылаясь на вопрос выше и вопрос, предоставленный xtofl, у меня есть внутренний помощник, который будет возвращен вызовом, и имеет оператор%, который добавляет аргументы во внутренний список аргументов (как определено xtofl (stackoverflow.com/questions/1350657/). В своем деструкторе он выполняет итерацию по списку делегатов CDelegateCaller, но как эти аргументы будут переданы оператору делегата() таким образом, чтобы пользователю не нужно реализовывать несколько рекурсивных функций? 17.09.2009
  • Это проблема - вызывать operator() при каждом вызове operator%? Или требуется передать все аргументы сразу? В примере, который вы разместили, нет необходимости во временном объекте. Функция Call может возвращать ссылку на this и вызывать operator() при каждом вызове operator%. 17.09.2009
  • Да, идея состоит в том, чтобы иметь возможность вызывать одну функцию делегата со всеми параметрами. Простой тестовый пример может быть реализован с несколькими вызовами, поскольку он просто выводит строку, но фактическое намерение состоит в том, чтобы вызвать более сложные функции. 18.09.2009

  • 2

    Из ответа Кирилла можно сделать вывод, что можно создать типобезопасный делегат, использующий шаблонную функцию объединения аргументов. Эта функция также нуждается в фиктивной отправной точке, но имеет преимущество безопасности типов.

    Библиотека FastFormat использует это, boost использует это, и я однажды предоставил другой пример в ответ на другой вопрос.

    17.09.2009
  • Спасибо, я посмотрел ваши шаблоны ArgList, см. комментарии к ответу Кирилла. 17.09.2009
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..