Повторно використовувати той самий код, щоб зробити ту саму логіку на різних членах даних objcets у списку

зокрема, я маю список об'єктів класу з кількома членами даних рядкового об'єкта (NID, CustomerNumber, studentNumber, fName, lName).

Я хочу повторно використати наступний код, щоб шукати вузол, який збігається з ключовим словом, незалежно від того, чи шуканий користувачем даних є NID або будь-який інший член ряду даних класу.

nodePtr = firstPtr;
for(; nodePtr != NULL && nodePtr->str != str; nodePtr = nodePtr->nextPtr);

if(nodePtr != NULL)
    //the nodePtr points to the node that matches the search key
else
    //no node matched the search key

якщо це був PHP-код, я міг би використовувати значення змінної як ім'я іншої:

$node->${$var}

але в C ++ все одно потрібно повторно використовувати код?

1
@JoachimPileborg Як я можу використовувати шаблони? Параметри шаблонів є заповнювачами для типів, що не є змінними іменами!
додано Автор MTVS, джерело
@JoachimPileborg Як я можу використовувати шаблони? Параметри шаблонів є заповнювачами для типів, що не є змінними іменами!
додано Автор MTVS, джерело
@JoachimPileborg Як я можу використовувати шаблони? Параметри шаблонів є заповнювачами для типів, що не є змінними іменами!
додано Автор MTVS, джерело
Препроцесорні макроси? Шаблони?
додано Автор Some programmer dude, джерело
Препроцесорні макроси? Шаблони?
додано Автор Some programmer dude, джерело
Препроцесорні макроси? Шаблони?
додано Автор Some programmer dude, джерело
@csstd: Параметри шаблону можуть бути значеннями, а не типом; зокрема, вони можуть бути вказівниками для членів класу, що стане одним із способів вирішення вашої проблеми - якщо потрібне поле завжди відоме під час компіляції. В іншому випадку, як аргумент функції, можна передавати покажчик-член-елемент (або, більш гнучко, об'єкт функції предиката).
додано Автор Mike Seymour, джерело
@csstd: Параметри шаблону можуть бути значеннями, а не типом; зокрема, вони можуть бути вказівниками для членів класу, що стане одним із способів вирішення вашої проблеми - якщо потрібне поле завжди відоме під час компіляції. В іншому випадку, як аргумент функції, можна передавати покажчик-член-елемент (або, більш гнучко, об'єкт функції предиката).
додано Автор Mike Seymour, джерело
@csstd: Параметри шаблону можуть бути значеннями, а не типом; зокрема, вони можуть бути вказівниками для членів класу, що стане одним із способів вирішення вашої проблеми - якщо потрібне поле завжди відоме під час компіляції. В іншому випадку, як аргумент функції, можна передавати покажчик-член-елемент (або, більш гнучко, об'єкт функції предиката).
додано Автор Mike Seymour, джерело

14 Відповіді

Подібно до std :: find_if :

template
N* my_find_if(const N* head, P pred)
{
    N* ptr;
    for (ptr = head; ptr != nullptr && !pred(ptr); ptr = ptr->nextPtr)
        ;

    return ptr;
}

Можна назвати так:

my_find_if(firstPtr,
    [](Node* node){ return node->str == str; });

Змініть лямбда до потрібного вам вираження.

Звичайно, я краще рекомендую використовувати стандартні контейнери , а не створювати власний список . Тоді ви можете скористатися стандартним стандартом std :: find_if .

2
додано
Оскільки якийсь проміжний крок між прокаткою власного списку та використанням стандартного контейнера, можливо, потрібно розглянути можливість написання типу ітератора для його спеціального списку, і в цьому випадку він міг би також використовувати стандартні алгоритми.
додано Автор Frerich Raabe, джерело

Подібно до std :: find_if :

template
N* my_find_if(const N* head, P pred)
{
    N* ptr;
    for (ptr = head; ptr != nullptr && !pred(ptr); ptr = ptr->nextPtr)
        ;

    return ptr;
}

Можна назвати так:

my_find_if(firstPtr,
    [](Node* node){ return node->str == str; });

Змініть лямбда до потрібного вам вираження.

Звичайно, я краще рекомендую використовувати стандартні контейнери , а не створювати власний список . Тоді ви можете скористатися стандартним стандартом std :: find_if .

2
додано
Оскільки якийсь проміжний крок між прокаткою власного списку та використанням стандартного контейнера, можливо, потрібно розглянути можливість написання типу ітератора для його спеціального списку, і в цьому випадку він міг би також використовувати стандартні алгоритми.
додано Автор Frerich Raabe, джерело

Подібно до std :: find_if :

template
N* my_find_if(const N* head, P pred)
{
    N* ptr;
    for (ptr = head; ptr != nullptr && !pred(ptr); ptr = ptr->nextPtr)
        ;

    return ptr;
}

Можна назвати так:

my_find_if(firstPtr,
    [](Node* node){ return node->str == str; });

Змініть лямбда до потрібного вам вираження.

Звичайно, я краще рекомендую використовувати стандартні контейнери , а не створювати власний список . Тоді ви можете скористатися стандартним стандартом std :: find_if .

2
додано
Оскільки якийсь проміжний крок між прокаткою власного списку та використанням стандартного контейнера, можливо, потрібно розглянути можливість написання типу ітератора для його спеціального списку, і в цьому випадку він міг би також використовувати стандартні алгоритми.
додано Автор Frerich Raabe, джерело

Найбільш гнучким способом цього є надання предикату як параметра шаблону:

template 
Node * find_if(Node * node, Pred pred) {
    for (; node && !pred(node); node = node->next);
    return node;
}

У C ++ 11 ви можете викликати це за допомогою лямбда:

if (Node * node = find_if(first, [&](Node * n){return n->NID == nid;})) {
   //node points to the matching node
} else {
   //not found
}

або, якщо ви застрягли в минулі століття, об'єкт функції:

struct CompareNID {
    CompareNID(std::string nid) : nid(nid) {}
    bool operator() {Node * n) {return n->NID == nid;}

    std::string nid;
};

Node * node = find_if(first, CompareNID(nid));

або, оскільки всі ваші поля є рядками, ви можете пожертвувати гнучкістю для точності, використовуючи покажчики учасників, надаючи щось подібне до вашого прикладу PHP:

Node * find(Node * node, std::string Node::*member, std::string const & value) {
    for (; node && node->*member != value; node = node->next);
    return node;
}

Node * node = find(first, &Node::NID, nid);
2
додано
просто пропустив другий параметр у списку параметрів find_if
додано Автор MTVS, джерело
@ csstd: добре помічено Я думаю, що це правильно зараз.
додано Автор Mike Seymour, джерело

Найбільш гнучким способом цього є надання предикату як параметра шаблону:

template 
Node * find_if(Node * node, Pred pred) {
    for (; node && !pred(node); node = node->next);
    return node;
}

У C ++ 11 ви можете викликати це за допомогою лямбда:

if (Node * node = find_if(first, [&](Node * n){return n->NID == nid;})) {
   //node points to the matching node
} else {
   //not found
}

або, якщо ви застрягли в минулі століття, об'єкт функції:

struct CompareNID {
    CompareNID(std::string nid) : nid(nid) {}
    bool operator() {Node * n) {return n->NID == nid;}

    std::string nid;
};

Node * node = find_if(first, CompareNID(nid));

або, оскільки всі ваші поля є рядками, ви можете пожертвувати гнучкістю для точності, використовуючи покажчики учасників, надаючи щось подібне до вашого прикладу PHP:

Node * find(Node * node, std::string Node::*member, std::string const & value) {
    for (; node && node->*member != value; node = node->next);
    return node;
}

Node * node = find(first, &Node::NID, nid);
2
додано
просто пропустив другий параметр у списку параметрів find_if
додано Автор MTVS, джерело
@ csstd: добре помічено Я думаю, що це правильно зараз.
додано Автор Mike Seymour, джерело

Найбільш гнучким способом цього є надання предикату як параметра шаблону:

template 
Node * find_if(Node * node, Pred pred) {
    for (; node && !pred(node); node = node->next);
    return node;
}

У C ++ 11 ви можете викликати це за допомогою лямбда:

if (Node * node = find_if(first, [&](Node * n){return n->NID == nid;})) {
   //node points to the matching node
} else {
   //not found
}

або, якщо ви застрягли в минулі століття, об'єкт функції:

struct CompareNID {
    CompareNID(std::string nid) : nid(nid) {}
    bool operator() {Node * n) {return n->NID == nid;}

    std::string nid;
};

Node * node = find_if(first, CompareNID(nid));

або, оскільки всі ваші поля є рядками, ви можете пожертвувати гнучкістю для точності, використовуючи покажчики учасників, надаючи щось подібне до вашого прикладу PHP:

Node * find(Node * node, std::string Node::*member, std::string const & value) {
    for (; node && node->*member != value; node = node->next);
    return node;
}

Node * node = find(first, &Node::NID, nid);
2
додано
просто пропустив другий параметр у списку параметрів find_if
додано Автор MTVS, джерело
@ csstd: добре помічено Я думаю, що це правильно зараз.
додано Автор Mike Seymour, джерело

Так, ви хочете передати в 2 лямбда (C ++ 11) або об'єкти, які можна запускати (C ++ 03) у ваш алгоритм "find".

За допомогою C ++ 03 ви можете перейти до двох функцій підвищення, один для випадку "знайдено" та один для випадку "не знайдено".

void search( std::string str, 
            boost::function ifFound, 
           boost::function ifNotFound )
{
      //search
     if( nodePtr != NULL )
     {
          ifFound();
     }
     else
     {
          ifNotFound();
     }
}

Виберіть свої підписи для відповідності, але так ви переходите в динамічні функції.

Ви можете використовувати std :: function замість boost :: function .

Якщо це саме пошукове середовище, яке ви хочете зробити гнучким, тобто те, яку частину об'єкта ви намагаєтеся зіставити, використовуйте також динамічний предикат.

void search( Pred pred// , ifFound, ,ifNotFound )
{
     if( pred( nodePtr ) )//then it is found
}

Пріакатор, як бачите, займе вказівник вузла і поверне true/false. Таким чином, різні судження будуть використовуватися для відповідності різним членам даних.

Хоча вам дійсно подобається поняття "багаторазовий код", я б рекомендував вам використовувати стандартну бібліотеку.

Якщо ваші списки є довгими, і ви постійно виконуєте ці пошуки, пошук вручну відбувається повільно, і ви можете використовувати boost :: multi_index , щоб створювати пошукові запити часу log-N у різних полях.

1
додано

Так, ви хочете передати в 2 лямбда (C ++ 11) або об'єкти, які можна запускати (C ++ 03) у ваш алгоритм "find".

За допомогою C ++ 03 ви можете перейти до двох функцій підвищення, один для випадку "знайдено" та один для випадку "не знайдено".

void search( std::string str, 
            boost::function ifFound, 
           boost::function ifNotFound )
{
      //search
     if( nodePtr != NULL )
     {
          ifFound();
     }
     else
     {
          ifNotFound();
     }
}

Виберіть свої підписи для відповідності, але так ви переходите в динамічні функції.

Ви можете використовувати std :: function замість boost :: function .

Якщо це саме пошукове середовище, яке ви хочете зробити гнучким, тобто те, яку частину об'єкта ви намагаєтеся зіставити, використовуйте також динамічний предикат.

void search( Pred pred// , ifFound, ,ifNotFound )
{
     if( pred( nodePtr ) )//then it is found
}

Пріакатор, як бачите, займе вказівник вузла і поверне true/false. Таким чином, різні судження будуть використовуватися для відповідності різним членам даних.

Хоча вам дійсно подобається поняття "багаторазовий код", я б рекомендував вам використовувати стандартну бібліотеку.

Якщо ваші списки є довгими, і ви постійно виконуєте ці пошуки, пошук вручну відбувається повільно, і ви можете використовувати boost :: multi_index , щоб створювати пошукові запити часу log-N у різних полях.

1
додано

Так, ви хочете передати в 2 лямбда (C ++ 11) або об'єкти, які можна запускати (C ++ 03) у ваш алгоритм "find".

За допомогою C ++ 03 ви можете перейти до двох функцій підвищення, один для випадку "знайдено" та один для випадку "не знайдено".

void search( std::string str, 
            boost::function ifFound, 
           boost::function ifNotFound )
{
      //search
     if( nodePtr != NULL )
     {
          ifFound();
     }
     else
     {
          ifNotFound();
     }
}

Виберіть свої підписи для відповідності, але так ви переходите в динамічні функції.

Ви можете використовувати std :: function замість boost :: function .

Якщо це саме пошукове середовище, яке ви хочете зробити гнучким, тобто те, яку частину об'єкта ви намагаєтеся зіставити, використовуйте також динамічний предикат.

void search( Pred pred// , ifFound, ,ifNotFound )
{
     if( pred( nodePtr ) )//then it is found
}

Пріакатор, як бачите, займе вказівник вузла і поверне true/false. Таким чином, різні судження будуть використовуватися для відповідності різним членам даних.

Хоча вам дійсно подобається поняття "багаторазовий код", я б рекомендував вам використовувати стандартну бібліотеку.

Якщо ваші списки є довгими, і ви постійно виконуєте ці пошуки, пошук вручну відбувається повільно, і ви можете використовувати boost :: multi_index , щоб створювати пошукові запити часу log-N у різних полях.

1
додано

Можливо, ви хочете використовувати вказівник-користувача:

typedef string Node::*NodeStringPtr;
NodeStringPtr nodeStrPtr = nullptr;
std::vector nodeStrings {&Node::NID, &Node::str, &Node::fName};
for (auto& ptr : nodeStrings)
{
  nodePtr = firstPtr;
  for (; nodePtr != NULL && nodePtr->*ptr != str; nodePtr = nodePtr->nextPtr);
  if (nodePtr)
  {
    nodeStrPtr = ptr;
    break;
  }
}

if(nodePtr != NULL)
    //the nodePtr matches the search key, nodeStrPtr matches the element
else
    /* ...*/
0
додано

Можливо, ви хочете використовувати вказівник-користувача:

typedef string Node::*NodeStringPtr;
NodeStringPtr nodeStrPtr = nullptr;
std::vector nodeStrings {&Node::NID, &Node::str, &Node::fName};
for (auto& ptr : nodeStrings)
{
  nodePtr = firstPtr;
  for (; nodePtr != NULL && nodePtr->*ptr != str; nodePtr = nodePtr->nextPtr);
  if (nodePtr)
  {
    nodeStrPtr = ptr;
    break;
  }
}

if(nodePtr != NULL)
    //the nodePtr matches the search key, nodeStrPtr matches the element
else
    /* ...*/
0
додано

Інший спосіб полягає в тому, щоб використовувати покажчики для членів (можливо, тільки якщо всі учасники одного типу):

struct Item {
    std::string NID,
                customerNumber,
                studentNumber,
                fName,
                lName;
};

typedef std::vector::iterator nodePtr;

typedef std::string Item::* MemberPtr;

struct List {
    std::vector list;

    nodePtr search(const std::string& str, MemberPtr mem_ptr)
    {
       //this is the code you want to reuse, I took the liberty and used
       //standard lib's algorithm
        return std::find_if(list.begin(), list.end(),
                            [&](const Item& item){ return str == item.*mem_ptr; });
       //will return list.end() if it doesn't find anything
    }
};

int main()
{
    List lst;
    lst.search("John", &Item::fName);
    lst.search("Doe", &Item::lName);
    lst.search("42", &Item::customerNumber);
}

Я думаю, що це найближче до вашого прикладу PHP.

0
додано

Інший спосіб полягає в тому, щоб використовувати покажчики для членів (можливо, тільки якщо всі учасники одного типу):

struct Item {
    std::string NID,
                customerNumber,
                studentNumber,
                fName,
                lName;
};

typedef std::vector::iterator nodePtr;

typedef std::string Item::* MemberPtr;

struct List {
    std::vector list;

    nodePtr search(const std::string& str, MemberPtr mem_ptr)
    {
       //this is the code you want to reuse, I took the liberty and used
       //standard lib's algorithm
        return std::find_if(list.begin(), list.end(),
                            [&](const Item& item){ return str == item.*mem_ptr; });
       //will return list.end() if it doesn't find anything
    }
};

int main()
{
    List lst;
    lst.search("John", &Item::fName);
    lst.search("Doe", &Item::lName);
    lst.search("42", &Item::customerNumber);
}

Я думаю, що це найближче до вашого прикладу PHP.

0
додано

Інший спосіб полягає в тому, щоб використовувати покажчики для членів (можливо, тільки якщо всі учасники одного типу):

struct Item {
    std::string NID,
                customerNumber,
                studentNumber,
                fName,
                lName;
};

typedef std::vector::iterator nodePtr;

typedef std::string Item::* MemberPtr;

struct List {
    std::vector list;

    nodePtr search(const std::string& str, MemberPtr mem_ptr)
    {
       //this is the code you want to reuse, I took the liberty and used
       //standard lib's algorithm
        return std::find_if(list.begin(), list.end(),
                            [&](const Item& item){ return str == item.*mem_ptr; });
       //will return list.end() if it doesn't find anything
    }
};

int main()
{
    List lst;
    lst.search("John", &Item::fName);
    lst.search("Doe", &Item::lName);
    lst.search("42", &Item::customerNumber);
}

Я думаю, що це найближче до вашого прикладу PHP.

0
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147