1

I was writing out the function below, and started to think that there's probably a better way to go about it; however Google isn't turning up much, so any insight would be appreciated. I also have a very similar situation involving integers.

bool compare_strs (std::string operator_, std::string str_0, std::string str_1)
{
    if (operator_ == ">")
    {
        return str_0 > str1;
    }
    else if (operator_ == "<")
    {
        return str_0 < str1;
    }
    else if (operator_ == "<=")
    {
        return str_0 <= str1;
    }
    else
    {
        return str_0 >= str1;
    }
}
9
  • Does the operator have to be a string? Commented Oct 12, 2012 at 19:35
  • 5
    Your variable names make baby Bjarne Stroustrup cry. Also, what happens if someone passes 'lol' for operator_? It will behave like '>='. This is probably not intended behavior. Furthermore, why do you need to do this? It would help if you posted more code. Commented Oct 12, 2012 at 19:36
  • 2
    You could make a std::map<std::string, std::function<bool(const std::string &, const std::string &>> to store them. There's already premade operator functors in <functional>. Commented Oct 12, 2012 at 19:38
  • 7
    @Wug your spelling of Bjarne makes him cry. Commented Oct 12, 2012 at 19:38
  • @chris: The question is not tagged C++11, but it's still a good suggestion that can be adapted to any standard with slightly different syntax. Commented Oct 12, 2012 at 19:39

2 Answers 2

3

You can use a map to store operators and related functors. In C++11, something along these lines should work, though there might be a couple subtle errors. In C++03, you'll have to change a couple things, including changing std::function to boost::function or function pointers, as well as using std::make_pair to store the map values.

#include <functional> //for std::function and std::less et al.
#include <map> //for std::map
#include <stdexcept> //for std::invalid_argument
#include <string> //for std::string

struct StringComparer {
    static bool compare( //split up to fit width
        const std::string &oper, 
        const std::string &str0, const std::string &str1
    ) {
        MapType::const_iterator iter = operations.find(oper); 
        if (iter == std::end(operations)) //check if operator is found
            throw std::invalid_argument("No match for provided operator.");

        return iter->second(str0, str1); //call the appropriate functor
    }

private:
    using MapType = std::map< //makes life easier, same as typedef
        std::string, 
        std::function<bool(const std::string &, const std::string &)>
    >;

    static const MapType operations; //a map of operators to functors
};

const StringComparer::MapType StringComparer::operations = { //define the map
    {"<", std::less<std::string>()}, //std::less is a functor version of <
    {"<=", std::less_equal<std::string>()},
    {">", std::greater<std::string>()},
    {">=", std::greater_equal<std::string>()}
};

You can also see it in action. The nice thing about an approach like this is that it's very easy to include more operators, as all you have to do is add them to the map.

Sign up to request clarification or add additional context in comments.

6 Comments

+1 because I didn't know about <functional>. That's quite neat. Do std::less etc automatically cast to integer or perform a string logical operation? (which I'd assume would be a character-wise comparison until one string terminated)
@slugonamission, To put it bluntly, Uses operator< on type T.. See a reference.
So yes, performs the logical operation on the templated type. Still neat :). Cheers.
@slugonamission, It's whole use is for something along these lines. Consider std::map itself, which requires being sorted. You can specify std::greater<T> as an optional argument to the constructor to have it ordered backwards, but all it is is a default parameter that defaults to std::less<T>.
Minor optimization: You should store the result of operations.find(oper) instead of going through the map a second time using operations[oper].
|
0

As others have mentioned, you should first ask yourself why you are doing this - there is likely a better solution. Going with this though, I might do something like:

template <typename T1, typename T2>
bool mycompare(std::string operator_, const T1 & _lhs, const T2 & _rhs)
{
    if (operator_ == ">")
    {
        return _lhs > _rhs;
    }
    else if (operator_ == "<")
    {
        return _lhs < _rhs;
    } 
    //etc.
    else
    {
        throw new exception("Invalid operator");
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.