Вы вероятно должны добиться этого с
bool firstIsEarlier(std::string first, std::string second) {
return first < second;
}
или в более общем плане с std::lexicographical_compare
.
Вы можете сделать точно то, что вы просите с помощью шаблонов выражений, и я покажу вам, как это сделать.
Есть несколько ограничений, хотя:
Вы не можете создавать новые операторы, так что вы должны выбрать два операторов, которые вы хотите перегружать: один для сравнения листьев и один для короткое замыкание.
(Вы можете использовать один оператор, если вы действительно хотели, но это было бы (даже больше) сбивает с толку и требует много скобок)
вы не можете сделать это, когда оба операнда являются примитивы , Если вы можете, ваш код будет выглядеть следующим образом:
bool firstIsEarlier(std::string first, std::string second){
return first[0]^second[0] <<= first[1]^second[1] <<= first[2]^second[2];
}
, но на самом деле вы должны были бы обернуть char
с в некотором значении контейнера для его работы.
Во-первых, нам нужно простое с тремя состояниями типа. Мы можем просто перечислить его:
enum class TriState {
True = -1,
Maybe = 0,
False = 1
};
Далее, нам необходимо некоторое вещь представлять наше выражение first[0]^second[0]
листа, которое приводится к нашему типу с тремя состояниями:
template <typename LHS, typename RHS>
struct TriStateExpr {
LHS const &lhs_;
RHS const &rhs_;
TriStateExpr(LHS const &lhs, RHS const &rhs) : lhs_(lhs), rhs_(rhs) {}
operator bool() const { return lhs_ < rhs_; }
operator TriState() const {
return (lhs_ < rhs_ ? TriState::True :
(rhs_ < lhs_ ? TriState::False : TriState::Maybe)
);
}
};
Обратите внимание, что мы просто требуя рабочего operator<
для наших типов - мы могли бы обобщить это, чтобы использовать явный компаратор, если это необходимо.
Теперь нам нужна нелистная часть дерева выражений. Я принуждаю его к дереву выражений справа налево, поэтому левое выражение всегда является листом, а правое выражение может быть листом или полным поддеревом.
template <typename LLHS, typename LRHS, typename RHS>
struct TriStateShortCircuitExpr {
TriStateExpr<LLHS, LRHS> const &lhs_;
RHS const &rhs_;
TriStateShortCircuitExpr(TriStateExpr<LLHS, LRHS> const &lhs, RHS const &rhs)
: lhs_(lhs), rhs_(rhs)
{}
operator TriState() const {
TriState ts(lhs_);
switch (ts) {
case TriState::True:
case TriState::False:
return ts;
case TriState::Maybe:
return TriState(rhs_);
}
}
operator bool() const {
switch (TriState(lhs_)) {
case TriState::True:
return true;
case TriState::False:
return false;
case TriState::Maybe:
return bool(rhs_);
}
}
};
Теперь вам нужен синтаксический сахар, поэтому нам нужно выбрать, какие операторы перегружать. Я буду использовать ^
для листьев (на том основании, что это как <
поворачивается на 90 градусов по часовой стрелке):
template <typename LHS, typename RHS>
TriStateExpr<LHS, RHS> operator^ (LHS const &l, RHS const &r) {
return TriStateExpr<LHS, RHS>(l,r);
}
и <<=
для не листиков:
template <typename LLHS, typename LRHS, typename RLHS, typename RRHS>
TriStateShortCircuitExpr<LLHS, LRHS, TriStateExpr<RLHS, RRHS>>
operator<<= (TriStateExpr<LLHS, LRHS> const &l,
TriStateExpr<RLHS, RRHS> const &r) {
return TriStateShortCircuitExpr<LLHS, LRHS, TriStateExpr<RLHS, RRHS>>(l, r);
}
template <typename LLHS, typename LRHS, typename... RARGS>
TriStateShortCircuitExpr<LLHS, LRHS, TriStateShortCircuitExpr<RARGS...>>
operator<<= (TriStateExpr<LLHS, LRHS> const &l,
TriStateShortCircuitExpr<RARGS...> const &r) {
return TriStateShortCircuitExpr<LLHS, LRHS,
TriStateShortCircuitExpr<RARGS...>>(l, r);
}
Основные соображения о том, что оператор листа должен в идеале иметь более высокий приоритет, а оператор, не связанный с листом, должен связывать права налево. Если вместо этого вы использовали ассоциативный оператор слева направо, TriStateShortCircuitExpr::operator
рекурсивно выполнил бы левый поддерево, что кажется неэлегантным для этого приложения.
Я не понимаю, как вы сообщаете о необходимости продолжения тестирования в приведенном выше примере? –
'true',' false' и '0'? Вопрос неясен! – Ajay
@MarcoA. если 'first [0]' - тот же символ, что и 'second [0]' Мне нужно пройти тест следующего символа. В блоках 'if'-'sese if' я использую тот факт, что если символы совпадают, результат их вычитания будет равен 0. –