[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 60e0657 1/5: Experimentally implement certain
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 60e0657 1/5: Experimentally implement certain compound assignment operators |
Date: |
Sun, 21 Mar 2021 21:10:52 -0400 (EDT) |
branch: master
commit 60e06577fd28d7352a6a68952be2feaecfbebe50
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>
Experimentally implement certain compound assignment operators
For PETE with std::vector, overloading std::vector::operator=() to
take a PETE Expression argument is not permitted because operator=()
must be a member, and altering namespace std is generally forbidden.
However, this:
assign(std::vector<T> lhs, Expression<T>);
is ugly and cumbersome.
It is permitted to overload compound assignment operators because
they needn't be members. Two are implemented here, experimentally:
operator<<(): This is somewhat reminiscent of stream inserters.
It cannot clash with PETE because PETE normally avoids defining
shift operators.
operator<<=(): This is also somewhat reminiscent of stream inserters,
yet is clearly an assignment operator. Compared to operator<<(), it
has an even lower precedence, which is an important advantage; it
requires typing an extra character; and it looks weirder, but that's
an advantage because it tells newcomers they'd better look it up in
lmi's documentation. It seems to work without modifying PETE (perhaps
because this implementation is more specialized?), but it would be
better to excise shift-assignment operators from PETE.
operator^=() (not implemented): This would be one character shorter
than operator<<=(), but that seems to be the only point in its favor.
Its connotation is more confusing: there's no operator^(std::ostream&)
to suggest at any unusual meaning, and outside of C++ '^' suggests
exponentiation.
In light of those advantages and disadvantages, operator<<=() seems
preferable.
See 'expression_template_0_test.cpp' for an earlier experiment.
---
et_vector_test.cpp | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/et_vector_test.cpp b/et_vector_test.cpp
index fd8daa3..8a86b09 100644
--- a/et_vector_test.cpp
+++ b/et_vector_test.cpp
@@ -25,6 +25,26 @@
#include <functional> // multiplies(), negate(), plus()
+// Experimental operators.
+//
+// See 'expression_template_0_test.cpp' for an earlier implementation
+// of operator<<().
+
+template<typename T, typename U>
+inline std::vector<T>& operator<<(std::vector<T>& t, Expression<U> const& u)
+{
+#if defined PETE_ALLOW_SCALAR_SHIFT
+# error PETE_ALLOW_SCALAR_SHIFT must not be defined.
+#endif // defined PETE_ALLOW_SCALAR_SHIFT
+ return assign(t, u);
+}
+
+template<typename T, typename U>
+inline std::vector<T>& operator<<=(std::vector<T>& t, Expression<U> const& u)
+{
+ return t = Eval(u);
+}
+
int test_main(int, char*[])
{
{
@@ -66,6 +86,21 @@ int test_main(int, char*[])
LMI_TEST(r1 == y);
}
+ // Test experimental operator<<() and operator<<=().
+ {
+ std::vector<double> v0 = {1.0, 1.25, 1.5};
+ std::vector<double> v1 = {0.0, 0.25, 0.5};
+ std::vector<double> x(3);
+// assign(x, v0 + v1);
+ x << v0 + v1;
+ std::vector<double> y(3);
+ y <<= v0 + v1 + x;
+ std::vector<double> const r0 = {1.0, 1.5, 2.0};
+ LMI_TEST(r0 == x);
+ std::vector<double> const r1 = {2.0, 3.0, 4.0};
+ LMI_TEST(r1 == y);
+ }
+
// Test peteCast().
{
std::vector<double> v0 = {0.0, 1.25, 2.5};