найти элемент в std :: vector из std :: any - PullRequest
6 голосов
/ 08 марта 2019

Я хочу проверить, существует ли элемент в векторе или нет.Я знаю, что следующий фрагмент кода проверит это.

#include <algorithm>

if ( std::find(vector.begin(), vector.end(), item) != vector.end() )
   std::cout << "found";
else
   std::cout << "not found";

Но у меня есть вектор любого типа.то есть std::vector<std::any> Я помещаю элементы в вектор следующим образом.

std::vector<std::any> temp;
temp.emplace_back(std::string("A"));
temp.emplace_back(10);
temp.emplace_back(3.14f);

Поэтому мне нужно найти, присутствует ли строка «A» в векторе или нет.Может ли std :: найти помощь здесь?

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

bool isItemPresentInAnyVector(std::vector<std::any> items, std::any item)
{
    for (const auto& it : items)
    {
        if (it.type() == typeid(std::string) && item.type() == typeid(std::string))
        {
            std::string strVecItem = std::any_cast<std::string>(it);
            std::string strItem = std::any_cast<std::string>(item);

            if (strVecItem.compare(strItem) == 0)
                return true;
        }
        else if (it.type() == typeid(int) && item.type() == typeid(int))
        {
            int iVecItem = std::any_cast<int>(it);
            int iItem = std::any_cast<int>(item);

            if (iVecItem == iItem)
                return true;
        }
        else if (it.type() == typeid(float) && item.type() == typeid(float))
        {
            float fVecItem = std::any_cast<float>(it);
            float fItem = std::any_cast<float>(item);

            if (fVecItem == fItem)
                return true;
        }
    }

    return false;
}

Ответы [ 4 ]

4 голосов
/ 08 марта 2019

Это должно работать хорошо, я думаю:

#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>

int main(){
    std::vector<std::any> temp;
    temp.emplace_back(std::string("A"));
    temp.emplace_back(10);
    temp.emplace_back(3.14f);

    int i = 10;//you can use any type for i variable and it should work fine
    //std::string i = "A"; 
    auto found = std::find_if(temp.begin(), temp.end(), [i](const auto &a){
        return typeid(i) == a.type() && std::any_cast<decltype(i)>(a) == i;
    } );

    std::cout << std::any_cast<decltype(i)>(*found);
}

Или сделать код немного более универсальным и многократно используемым:

#include <vector>
#include <string>
#include <any>
#include <algorithm>
#include <iostream>


auto any_compare = [](const auto &i){
    return [i] (const auto &val){
        return typeid(i) == val.type() && std::any_cast<decltype(i)>(val) == i;
    };
};

int main(){
    std::vector<std::any> temp;
    temp.emplace_back(std::string("A"));
    temp.emplace_back(10);
    temp.emplace_back(3.14f);

    //int i = 10;
    std::string i = "A";
    auto found = std::find_if(temp.begin(), temp.end(), any_compare(i));

    std::cout << std::any_cast<decltype(i)>(*found);
}

Живая демоверсия

Важное примечание: это гарантированно работает только в пределах одной единицы перевода из-за стандартных требований к типу std::any (например, одинаковые типы не должны иметь одинаковый идентификатор типа в разных единицах перевода)

2 голосов
/ 08 марта 2019

К сожалению, если вы хотите найти экземпляр std::any в векторе std::any экземпляров, ответ - нет.

std::any нужна некоторая «магия», например, чтобы иметь возможность обрабатывать создание неизвестных типов объектов, но этот механизм является частным и должен поддерживать только создание объектов, а не сравнение на равенство.

Было бы возможно реализовать то, что вы ищете, используя тот же подход, но не со стандартным std::any, который не публикует необходимые детали. Шаблон "manager" должен перечислять все возможные операции, и, например, в реализации g ++ это "access", "get_type_info", "clone", "destroy", "xfer".

variant полностью отличается, потому что явно перечисляет все разрешенные типы и, следовательно, в любом месте, где он используется, имеет доступ ко всем методам.

1 голос
/ 08 марта 2019

Использование any для такого рода целей не является хорошим использованием any. Лучший способ - просто использовать variant - поскольку у вас есть закрытый набор типов:

struct Equals {
    template <typename T>
    constexpr bool operator()(T const& a, T const& b) const { return a == b; }

    template <typename T, typename U>
    constexpr bool operator()(T const& a, U const& b) const { return false; }
};

using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
    auto it = std::find_if(items.begin(), items.end(), [&](V const& elem){
        return std::visit(Equals{}, elem, item);
    });
    return it != items.end();
}

На самом деле это даже лучше, потому что, как указывает Килиан, variant s operator== уже работает именно так:

using V = std::variant<int, float, std::string>
bool isItemPresentInAnyVector(std::vector<V> const& items, V const& item)
{
    return std::find(items.begin(), items.end(), item) != items.end();
}
0 голосов
/ 08 марта 2019

Если типами являются int, float и string (или ограниченный набор типов), вы можете использовать комбинацию std::variant и std::get_if для достижения того, что вы хотите сделать в простом Способ:

std::get_if - определить, какой из типов хранится в std::variant.

Минимальный пример:

#include <iostream>
#include <vector>
#include <string>
#include <variant>

int main(){
    std::vector<std::variant<int, float, std::string>> temp;
    temp.emplace_back(std::string("A"));
    temp.emplace_back(10);
    temp.emplace_back(3.14f);     

    for (const auto& var: temp) {
      if(std::get_if<std::string>(&var)) { 
          if(std::get<std::string>(var) == "A") std::cout << "found string\n"; 
      }
      if(std::get_if<int>(&var)) { 
          if(std::get<int>(var) == 10) std::cout << "found int\n"; 
      }
      if(std::get_if<float>(&var)) { 
          if(std::get<float>(var) == 3.14f) std::cout << "found float\n"; 
      }
    }
}

Демонстрация в реальном времени

...