некоторым бинарным оператором
Условие ассоциативности:
(A ∘ B) ∘ C = A ∘ (B ∘ C)
, где A, B и C - произвольные элементы,
∘ - бинарная операция/метод или функция принимающая два аргумента;
у меня будет метод/функция/структура, которая будет проверять проверять ассоциативность бинарного оператора в связке с конкретными типами элементов, условно говоря
template <typename T1, typename T2, typename T3 /*может что-то ещё?*/>
bool is_associative(/*нужно как-то передать оператор*/) {
...
return (A ∘ B) ∘ C = A ∘ (B ∘ C);
}
передать тип просто - обычным шаблоном, а вот как передать бинарный оператор? ещё я хотел бы сделать так чтобы оператор мог быть кастомным, но это, думаю, можно разрешить специализацией/перегрузкой
у меня есть 3 условных класса:
struct A; // втутри реализовны бинарные операции, условно operator+(...) для классов B и C
struct B; // втутри реализовны бинарные операции, условно operator+(...) для классов A и C
struct C; // втутри реализовны бинарные операции, условно operator+(...) для классов A и B
+ должна быть возможность сравнивать результат вычисления левой и правой стороны условия ассоциативности
и каждый из классов определяет как н будет взаимодействовать с другим классом посредством бинарного оператора/функции/метода + каждый из классов определяет операцию сравнения с другим классом, но это не так важно, так как в комбинации (A ∘ B) ∘ C может образовываться совместный тип, и операция сравнения с другой стороной условия ассоциативности(A ∘ (B ∘ C)) будет выполняться между другими типами
допустим это будет бинарная операция +, тогда метод/структура должны проверить следующее утверждение:
(A ∘ B) ∘ C = A ∘ (B ∘ C)
(A.operator+(B)).operator+(C) == A.operator+(B.operator+(C)) + ещё 5 вариантов с перестановкой элементов A, B и C
либо
operator+(operator+(A, B), C) == operator+(A, operator+(B, C)) + ещё 5 вариантов с перестановкой элементов A, B и C
собственно как можно передать бинарную операцию/метод или функцию принимающую два аргумента?
Смотрите: оператор T1, T2 -> Т(1_2), оператор Т(1_2), Т3 -> Т((1_2)_3), оператор Т2, Т3 -> Т(2_3), оператор Т1, Т(2_3) -> T(1_(2_3)). Итого у вас целых 4 разных оператора, а вовсе не 1, так как разные типы.
операторов на самом деле больше (как минимум 6), но в этом и суть вопроса, как обобщить
в общем это работает, но нужно передавать довольно много operator+ для разных комбинаций типа, что в целом неудобно хотелось бы делать это через какой-нибудь шаблон функции, который параметризировался внутри самой функции template <typename T1, typename T2, typename T3, template <typename, typename> typename Func> bool is_associative () { Func<T1, T2>; Func<T1, T3>; Func<T2, T1>; Func<T2, T3>; Func<T3, T1>; Func<T3, T2>; // условие - затычка bool result = Func(Func(T1{5}, T2{4}), T3{7}) == Func(Func(T1{5}, T2{4}), T3{7}); return result; }; template <typename T1, typename T2> auto func(T1 lhs, T2 rhs) { return lhs + rhs; } int main() { bool result = is_associative<Obj1, Obj2, Obj3, decltype(func)(???)>(); } вот я пытался что-то сделать: https://godbolt.org/z/9jGPb6bP4
Заверни в функцию, функцию передавай, функция это если что тип данных.
надо чтобы в функцию is_associative можно было передать кучу всяких операторов, у которых разные типы на входе и выходе да?
Можно посмотреть в сторону std::plus
Да, именно так
Я смотрел, но проблема в том, что его просто так не передашь, перед передачей его нужно параметризировать -> параметризированный std::plus будет работать только для одной из множества пар аргументов
та же проблема, либо нужно создавать 6(???) параметризированных функций и передавать их, либо использовать какой-то неизвестный мне механизм
Что, проблема написать 6 функций ?
написать 6 функций не проблема, но как вы себе представляете работу с таким кодом? сама функция is_associative: template <typename T1, typename T2, typename T3> bool is_associative ( T1 (*Func12)(T1,T2), T1 (*Func13)(T1,T3), T2 (*Func21)(T2,T1), T2 (*Func23)(T2,T3), T3 (*Func31)(T3,T1), T3 (*Func32)(T3,T2)) { // условие - затычка bool result = Func13(Func12(T1{5}, T2{4}), T3{7}) == Func12(T1{5}, Func23(T2{4}, T3{7})); return result; }; шаблон функции, которую нужно параметризировать: template <typename T1, typename T2> auto func(T1 lhs, T2 rhs) { return lhs + rhs; } вызов функции is_associative: bool result = is_associative<Obj1, Obj2, Obj3>(func<Obj1, Obj2>, func<Obj1, Obj3>, func<Obj2, Obj1>, func<Obj2, Obj3>, func<Obj3, Obj1>, func<Obj3, Obj2>); MRE: https://godbolt.org/z/KaMG6GaWb
а вот так не подойдет? #include <iostream> #include <functional> struct A { A() = default; A(int v): val(v) {} /* A(const A& other): val(other.val) { std::cout << "copy\n"; } A(A&& other): val(other.val) { std::cout << "move\n"; } */ A& operator+=(const A& other) { val += other.val; return *this; } int val = 1; }; A operator+(A a, const A& b) { a += b; return a; } template <template <typename> typename F, typename T, typename U> auto operate(const T& a, const U& b) { return F()(a, b); } int main() { A a, b; A c = operate<std::plus>(a, b); std::cout << c.val << ' '; std::cout << operate<std::plus>(5, b).val; // 2 6 }
Всё оказалось проще чем могло показаться, нужно было всего лишь определить шаблонны оператор круглые скобки внутри структуры и передавать шаблон структуры как тип(странно, что нельзя передавать шаблон функции как тип) Ваш код очень помог, спасибо вам большое
std::plus<> будет работать для любых пар. Это объект с перегруженным шаблонным operator()
К сожалению я сразу подумал что std::plus это обычная шаблонная функция, и не придав этому значения подумал что это не то
Идейно, твоя задача как раз решается объектами, а не функциями, так как передать можно один объект, у которого будет пачка перегруженных операторов (или один шаблонный)
Обсуждают сегодня