C++ comparing bunch of values with a given one

后端 未结 10 916
一向
一向 2021-01-21 06:02

I need to compare one given value with a retrieved values. I do this several times in the code. I am not satisfied with how it looks and I am seeking for a some sort of an util

相关标签:
10条回答
  • 2021-01-21 06:58

    For your request to do

    if (InSet(value)(GetValue1(), GetValue2(), GetValue3()))
    {
       // Do something here...
    }
    

    Try this:

    template <typename T>
    class InSetHelper
    {
         const T &Value;
         void operator=(const InSetHelper &);
    public:
         InSetHelper(const T &value) : Value(value) {}
    
         template<class Other, class Another>
         bool operator()(const Other &value1, const Another &value2) const
         {
             return Value == value1 || Value == value2;
         }
         template<class Other, class Another, class AThird>
         bool operator()(const Other &value1, const Another &value2, const AThird &value3) const
         {
             return Value == value1 || Value == value2 || Value == value3;
         }
    };
    
    template <typename T> 
    InSetHelper<T> InSet(const T &value) { return InSetHelper<T>(value); }
    

    This syntax might be more clear though:

    if (MakeSet(GetValue1(), GetValue2(), GetValue3()).Contains(value))
    {
       // Do something here...
    }
    
    template <typename T, typename U, typename V>
    class Set3
    {
        const T& V1;
        const U& V2;
        const V& V3;
        void operator=(const Set3 &);
    public:
        Set3(const T &v1, const U &v2, const V &v3) : V1(v1), V2(v2), V3(v3) {}
    
        template <typename W>
        bool Contains(const W &v) const
        {
            return V1 == v || V2 == v || V3 == v;
        }
    };
    
    template <typename T, typename U>
    class Set2 
    { 
         // as above 
    };
    
    template <typename T, typename U, typename V>
    Set3<T, U, V> MakeSet(const T &v1, const U &v2, const V &v3)
    {
        return Set3<T, U, V>(v1, v2, v3);
    }
    
    template <typename T, typename U>
    Set3<T, U> MakeSet(const T &v1, const U &v23)
    {
        return Set3<T, U, V>(v1, v2);
    }
    

    If those values are really part of a tree or a linked list, then you have your set/container already, and your best bet is to just use some recursion:

    parent.ThisOrDescendantHasValue(value);
    

    You'd just add this to whatever class parent and child belong to:

    class Node
    {
    public: 
        Value GetValue();
        Node *GetChild();
        bool ThisOrDescendantHasValue(const Value &value)
        {
            return GetValue() == value
               || (GetChild() && GetChild->ThisOrDescendantHasValue(value));
        }
    };
    
    0 讨论(0)
  • 2021-01-21 07:00

    How about using a boost::array (or std::tr1::array) and creating a simple function like this:

    template <typename ValueType, size_t arraySize>
    bool contains(const boost::array<ValueType, arraySize>& arr, const ValueType& val)
    {
        return std::find(arr.begin(), arr.end(), val)!=arr.end();
    }
    

    You could then reuse that pretty easily:

    #include <string>
    #include <iostream>
    
    #include <boost\array.hpp>
    
    template <typename ValueType, size_t arraySize>
    bool contains(const boost::array<ValueType, arraySize>& arr, const ValueType& val)
    {
        return std::find(arr.begin(), arr.end(), val)!=arr.end();
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        boost::array<std::string, 3> arr = {"HI", "there", "world"};
    
        std::cout << std::boolalpha 
            << "arr contains HI: " << contains(arr, std::string("HI")) << std::endl
            << "arr contains blag: " << contains(arr, std::string("blag") ) << std::endl
            << "arr contains there: " << contains(arr, std::string("there") ) << std::endl;
    
        return 0;
    }
    

    Edit: So boost is out. It's pretty easy to adapt this to a regular array:

    template <typename ValueType, size_t arraySize>
    bool contains(ValueType (&arr)[arraySize], const ValueType& val)
    {
        return std::find(&arr[0], &arr[arraySize], val)!=&arr[arraySize];
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        std::string arr[3] = {"HI", "there", "world"};
    
        std::cout << std::boolalpha << "arr contains HI: " << contains(arr, std::string("HI")) << std::endl
            << "arr contains blag: " << contains(arr, std::string("blag") ) << std::endl
            << "arr contains there: " << contains(arr, std::string("there") ) << std::endl;
    
        return 0;
    }
    
    0 讨论(0)
  • 2021-01-21 07:01

    std::find_first_of.

    Of course, if you only care about finding a single value, you can create your own wrapper around std::find.

    0 讨论(0)
  • 2021-01-21 07:07

    I would recommend your method 2, using a std::vector or other container and looking for membership. Since the order of elements that you're checking against is probably not relevant, you may want to use a std::set or std::map. If you have very many items in your set of values, then using a set or a map will be a faster, while if you have only a few a vector may be faster.

    The advantage of any of these approaches is that you can then store the set/map somewhere common, and avoid having to build the set of matching responses every time.

    0 讨论(0)
提交回复
热议问题