C ++: Найти первый элемент кортежа, который удовлетворяет предикату - PullRequest
2 голосов
/ 20 апреля 2019

У меня есть следующий подробный код:

struct thing1 { int key, std::string value; };
struct thing2 { int key, std::string value; };
// ...
struct thingN { int key, std::string value; };

struct thing_map {
  thing1 t1;
  thing2 t2;
  // ...
  thingN tN;

  std::string get(int key) {
    if(t1.key == key) return t1.value;
    if(t2.key == key) return t2.value;
    // ...
    if(tN.key == key) return tN.value;
    throw std::runtime_error("bad key");
  }
};

Я могу реорганизовать thing s в std::tuple<thing1, thing2, /* ... */ thingN>, это позволяет мне получить к ним доступ с набранным std::get, поэтому никакой функциональностипотерял (то есть std::get<thing1>(things)).Я не могу понять, как реализовать каскад if.Существуют различные реализации функций, которые применяют функцию к каждому элементу кортежа в Интернете, но эти функции всегда используют пакет параметров индекса для сопоставления, поэтому я не могу выбрать один элемент и вернуть его значение.Тривиальная вещь, которую можно сделать, это, возможно, сохранить tN.value в захваченную переменную и вернуть ее, но у меня есть ощущение, что есть лучшее решение.

Для ясности я пытаюсь сделать следующее:

struct thing_map {
  std::tuple<thing1, thing2, /* ... */ thingN> things;

  std::string get(int key) {
    foreach(auto&& thing : things) {
      if (key == thing.key) return thing.value;
    }
    throw std::runtime_error("bad key");
  }
};

Я использую C ++ 17

1 Ответ

4 голосов
/ 20 апреля 2019

Вы можете использовать C ++ 17, поэтому я предлагаю использовать std::apply() и сворачивание шаблонов следующим образом

   std::string get(int key)
    {
      return std::apply([&](auto const & ... args)
       {
         std::string ret;

         ( ((key == args.key) ? (ret = args.value, true) : false)
           || ... || (throw std::runtime_error("bad key"), false) );

         return ret;
       }, things);
    }

Ниже приводится полный пример компиляции

#include <tuple>
#include <string>
#include <iostream>
#include <stdexcept>

struct thing1 { int key{1}; std::string value{"one"}; };
struct thing2 { int key{2}; std::string value{"two"}; };
struct thing3 { int key{3}; std::string value{"three"}; };
struct thing4 { int key{4}; std::string value{"four"}; };

struct thing_map
 {
   std::tuple<thing1, thing2, thing3, thing4> things;

   std::string get(int key)
    {
      return std::apply([&](auto const & ... args)
       {
         std::string ret;

         ( ((key == args.key) ? (ret = args.value, true) : false)
           || ... || (throw std::runtime_error("bad key"), false) );

         return ret;
       }, things);
    }
 };

int main ()
 {
   thing_map tm;

   std::cout << tm.get(1) << std::endl;
   std::cout << tm.get(2) << std::endl;
   std::cout << tm.get(3) << std::endl;
   std::cout << tm.get(4) << std::endl;
   std::cout << tm.get(5) << std::endl;
 }
...