bogorodniy's blog

By bogorodniy, history, 4 years ago, translation, In English

I wondered for a long time how to make different user-operators. For example write this x minEqual y instead of x = min(x, y)

So recently I've done this, and decided to share it with you.

#include <bits/stdc++.h>

using namespace std;
struct mineq_operator
{
    int tempVal=1000;
    inline mineq_operator operator<<(int& x)
    {
        this->tempVal = x;
        return *this;
    } inline mineq_operator operator>>(int& x)
    {
        x = min(x, tempVal);
        return *this;
    }
};
mineq_operator __me;
inline void operator<<(int& x, mineq_operator& b)
{
    b.tempVal = x;
}
#define minEqual <<__me;__me>>
signed main()
{
    int x = 3, y = 2;
    y minEqual x;
    cout << x << ' ' << y << endl;
}

For use it like x = min(x, y); just write y minEqual x;

And this in compressed format:

#include <bits/stdc++.h>

using namespace std;
struct mineq_operator {int tempVal=1000;inline mineq_operator operator<<(int& x) {this->tempVal = x;return *this;}inline mineq_operator operator>>(int& x) {x = min(x, tempVal);return *this;}};
mineq_operator __me; inline void operator<<(int& x, mineq_operator& b) {b.tempVal = x;}
#define minEqual <<__me;__me>>
signed main() {
  int x = 3, y = 2;
    y minEqual x;
    cout << x << ' ' << y << endl;
}

  • Vote: I like it
  • +61
  • Vote: I do not like it

»
4 years ago, # |
  Vote: I like it +23 Vote: I do not like it

wow thx, it is very useful!!

»
4 years ago, # |
  Vote: I like it +1 Vote: I do not like it

Auto comment: topic has been translated by bogorodniy (original revision, translated revision, compare)

»
4 years ago, # |
  Vote: I like it +4 Vote: I do not like it

very cool!

»
4 years ago, # |
  Vote: I like it +5 Vote: I do not like it

Some time ago I wrote

/*
/in/ shortcut
+ 2 in [1,2,3]
+ "ab" in "bacaba"
+ 'w' in "cow"
+ "key" in {"key": 123}_json
+ 42 in map<int, string>, set<int> (+unordered)
*/
namespace ultra {
    template<typename T>
    struct in_prefix_t {
        T const *pvalue = nullptr;
        explicit inline in_prefix_t(T const *pvalue) : pvalue(pvalue) { }
    };
    struct in_helper_t { };

} // namespace ultra

ultra::in_helper_t in;

template<typename T>
inline ultra::in_prefix_t<T> operator / (T const& value, ultra::in_helper_t) {
    return ultra::in_prefix_t<T>(&value);
}

template<typename T, typename Container>
inline bool operator / (ultra::in_prefix_t<T> prefix, Container const& cont) {
    return std::find(std::begin(cont), std::end(cont), *prefix.pvalue) != std::end(cont);
}

template<typename T>
inline bool operator / (ultra::in_prefix_t<T> prefix, std::string const& s) {
    return s.find(*prefix.pvalue) != string::npos;
}

inline bool operator / (ultra::in_prefix_t<char> prefix, std::string const& s) {
    return s.find(*prefix.pvalue) != string::npos;
}

template<typename T, typename U, typename V>
inline bool operator / (ultra::in_prefix_t<T> prefix, std::map<U, V> const& m) {
    return m.find(*prefix.pvalue) != m.end();
}

template<typename T, typename U>
inline bool operator / (ultra::in_prefix_t<T> prefix, std::set<U> const& s) {
    return s.find(*prefix.pvalue) != s.end();
}

template<typename T, typename U, typename V>
inline bool operator / (ultra::in_prefix_t<T> prefix, std::unordered_map<U, V> const& m) {
    return m.find(*prefix.pvalue) != m.end();
}

template<typename T, typename U>
inline bool operator / (ultra::in_prefix_t<T> prefix, std::unordered_set<U> const& s) {
    return s.find(*prefix.pvalue) != s.end();
}

template<typename T>
inline bool operator / (ultra::in_prefix_t<T> prefix, json s) {
    return s.count(*prefix.pvalue) != 0;
}

Pretty useless although :)

»
4 years ago, # |
  Vote: I like it +24 Vote: I do not like it

Interesting idea, execution leaves much to be desired.

1) You shouldn't put int& as the parameter type for operator>>, int will do just fine. In fact, you'll get compilation errors if you try to use an r-value as an operand, as in the example below.

2) After replacing int& with int, what does this print?

int computeSomething() {
	int z = 1000;
	z minEqual 100;
	return z;
}

signed main() {
  int x = 200, y = 300;
  y minEqual computeSomething();
  cout << x << ' ' << y << endl;
}
»
4 years ago, # |
Rev. 2   Vote: I like it +11 Vote: I do not like it

I made it a bit shorter (and also without bug, which ivan100sic mentioned)

Code

And this can be improved to work with any type:

Code

Actually, it is better to use operator ,, instead of operator ^ to avoid extra brackets (link)

By the way, my code creates structure on each minEqual, so probably it is slower than the original version, but I am not sure. However, if you aim for speed, you shouldn't use any of these options, I think.

  • »
    »
    4 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    You should return x in the first function ;)

    With -O2, the compiler will even get rid of all function calls, you can try it on godbolt.org

»
4 years ago, # |
  Vote: I like it +6 Vote: I do not like it

I suppose that I write x minEqual f(1, 2, 3); to minimize x by a result of function call f(1, 2, 3). Obviously it 1) will not compile and 2) might lead to undefined behavior if f(int, int, int) uses minEqual operator as well.

So that I just return to simpler alternative:

void minimize(int& a, int b)
{
    a = std::min(a, b);
}
...
    minimize(x, f(1, 2, 3));
...
»
4 years ago, # |
Rev. 2   Vote: I like it +1 Vote: I do not like it

And I use normal functions like these

/// I use _x_ instead of normal x to prevent from IntelliSense

/// a = min(a, b)
template<class _A_, class _B_>
void minimize(_A_ &_a_, const _B_ &_b_) { if (_a_ > _b_) _a_ = _b_; }

/// return true if (a is minimized to b)
template<class _A_, class _B_>
bool   ismini(_A_ &_a_, const _B_ &_b_) { if (_a_ > _b_) { _a_ = _b_; return true; } return false; }

/// a = min{b, ...}
template<class _A_, class _B_, class..._V_>
void minimize(_A_ &_a_, const _B_ &_b_, const _V_&..._v_) {
    minimize(_a_, _b_);
    minimize(_a_, _v_...);
}