除非您有大量具有复杂签名的运算符,所有这些运算符都需要复制以进行交换行为,否则我只会使用已接受答案中的解决方案。但是,如果你真的讨厌重复你的代码或者只是为了它而让它工作:
#include <iostream> // std::cout
#include <utility> // std::pair
#include <type_traits> // std::remove_cvref_t
#include <concepts> // std::same_as
// These two utilities will be used for all commutative functions:
template <typename T, typename U, typename V, typename W>
concept commutative =
(std::same_as<std::remove_cvref_t<T>, V> && std::same_as<std::remove_cvref_t<U>, W>) ||
(std::same_as<std::remove_cvref_t<U>, V> && std::same_as<std::remove_cvref_t<T>, W>);
template <typename V, typename W, typename T, typename U>
requires commutative<T, U, V, W>
constexpr decltype(auto) order (T && a, U && b) {
if constexpr (std::same_as<std::remove_cvref_t<T>, V>)
return std::pair{std::forward<T>(a), std::forward<U>(b)};
else
return std::pair{std::forward<U>(b), std::forward<T>(a)};
}
// Here goes the use-case:
struct A {
int aval;
};
struct B {
int bval;
};
// This template declaration allows two instantiations:
// (A const &, B const &) and (B const &, A const &)
template <typename T, commutative<T, A, B> U>
A operator + (T const & first, U const & second) {
// But now we need to find out which is which:
auto const & [a, b] = order<A, B>(first, second);
return {.aval = a.aval + b.bval};
}
// Just to test it:
int main () {
A a = {.aval = 1};
B b = {.bval = 2};
A c = a + b;
A d = b + a;
std::cout << c.aval << '\n';
std::cout << d.aval << '\n';
}
如果template <typename T, commutative<T, A, B> U>
并且auto const & [a, b] = order<A, B>(first, second);
与为您的场景重复整个定义相比,样板代码更少return b + a;
,那么我想它可能很有用。