Date: Thu, 12 Mar 2020 17:24:25 -0400
Again, here is a very powerful example with different numeric types,
their precedence with their regular and infix operators implemented only
once:
namespace numeric
{
template <typename Class, typename T>
inline Class::Class(T const & v) : value(v.value)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
}
template <typename Class, typename T>
inline T Class::operator + (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value + v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator - (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value - v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator * (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value * v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator / (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value / v.value;
return res;
}
template <typename Class, typename T>
inline T & Class::operator += (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator + (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator -= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator - (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator *= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator * (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator /= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator / (v);
return * this;
}
struct int_t;
struct double_t;
struct long_double_t;
struct int_t
{
int value;
int_t(int v) : value(v) {}
int_t(int_t const & v) = generic;
int_t operator + (int_t const & v) const = generic;
int_t operator - (int_t const & v) const = generic;
int_t operator * (int_t const & v) const = generic;
int_t operator / (int_t const & v) const = generic;
double_t operator + (double_t const & v) const = generic;
double_t operator - (double_t const & v) const = generic;
double_t operator * (double_t const & v) const = generic;
double_t operator / (double_t const & v) const = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
int_t & operator += (int_t const & v) = generic;
int_t & operator -= (int_t const & v) = generic;
int_t & operator *= (int_t const & v) = generic;
int_t & operator /= (int_t const & v) = generic;
};
struct double_t
{
double value;
double_t(double v) : value(v) {}
double_t(int_t const & v) = generic;
double_t(double_t const & v) = generic;
double_t operator + (double_t const & v) const = generic;
double_t operator - (double_t const & v) const = generic;
double_t operator * (double_t const & v) const = generic;
double_t operator / (double_t const & v) const = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
double_t & operator += (int_t const & v) = generic;
double_t & operator -= (int_t const & v) = generic;
double_t & operator *= (int_t const & v) = generic;
double_t & operator /= (int_t const & v) = generic;
double_t & operator += (double_t const & v) = generic;
double_t & operator -= (double_t const & v) = generic;
double_t & operator *= (double_t const & v) = generic;
double_t & operator /= (double_t const & v) = generic;
};
struct long_double_t
{
long double value;
long_double_t(long double v) : value(v) {}
long_double_t(int_t const & v) = generic;
long_double_t(double_t const & v) = generic;
long_double_t(long_double_t const & v) = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
long_double_t & operator += (int_t const & v) = generic;
long_double_t & operator -= (int_t const & v) = generic;
long_double_t & operator *= (int_t const & v) = generic;
long_double_t & operator /= (int_t const & v) = generic;
long_double_t & operator += (double_t const & v) = generic;
long_double_t & operator -= (double_t const & v) = generic;
long_double_t & operator *= (double_t const & v) = generic;
long_double_t & operator /= (double_t const & v) = generic;
long_double_t & operator += (long_double_t const & v) = generic;
long_double_t & operator -= (long_double_t const & v) = generic;
long_double_t & operator *= (long_double_t const & v) = generic;
long_double_t & operator /= (long_double_t const & v) = generic;
};
}
using numeric::int_t;
using numeric::double_t;
using numeric::long_double_t;
their precedence with their regular and infix operators implemented only
once:
namespace numeric
{
template <typename Class, typename T>
inline Class::Class(T const & v) : value(v.value)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
}
template <typename Class, typename T>
inline T Class::operator + (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value + v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator - (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value - v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator * (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value * v.value;
return res;
}
template <typename Class, typename T>
inline T Class::operator / (T const & v) const
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
T res;
res.value = value / v.value;
return res;
}
template <typename Class, typename T>
inline T & Class::operator += (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator + (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator -= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator - (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator *= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator * (v);
return * this;
}
template <typename Class, typename T>
inline T & Class::operator /= (T const & v)
{
std::clog << __PRETTY_FUNCTION__ << std::endl;
* this = this->operator / (v);
return * this;
}
struct int_t;
struct double_t;
struct long_double_t;
struct int_t
{
int value;
int_t(int v) : value(v) {}
int_t(int_t const & v) = generic;
int_t operator + (int_t const & v) const = generic;
int_t operator - (int_t const & v) const = generic;
int_t operator * (int_t const & v) const = generic;
int_t operator / (int_t const & v) const = generic;
double_t operator + (double_t const & v) const = generic;
double_t operator - (double_t const & v) const = generic;
double_t operator * (double_t const & v) const = generic;
double_t operator / (double_t const & v) const = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
int_t & operator += (int_t const & v) = generic;
int_t & operator -= (int_t const & v) = generic;
int_t & operator *= (int_t const & v) = generic;
int_t & operator /= (int_t const & v) = generic;
};
struct double_t
{
double value;
double_t(double v) : value(v) {}
double_t(int_t const & v) = generic;
double_t(double_t const & v) = generic;
double_t operator + (double_t const & v) const = generic;
double_t operator - (double_t const & v) const = generic;
double_t operator * (double_t const & v) const = generic;
double_t operator / (double_t const & v) const = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
double_t & operator += (int_t const & v) = generic;
double_t & operator -= (int_t const & v) = generic;
double_t & operator *= (int_t const & v) = generic;
double_t & operator /= (int_t const & v) = generic;
double_t & operator += (double_t const & v) = generic;
double_t & operator -= (double_t const & v) = generic;
double_t & operator *= (double_t const & v) = generic;
double_t & operator /= (double_t const & v) = generic;
};
struct long_double_t
{
long double value;
long_double_t(long double v) : value(v) {}
long_double_t(int_t const & v) = generic;
long_double_t(double_t const & v) = generic;
long_double_t(long_double_t const & v) = generic;
long_double_t operator + (long_double_t const & v) const = generic;
long_double_t operator - (long_double_t const & v) const = generic;
long_double_t operator * (long_double_t const & v) const = generic;
long_double_t operator / (long_double_t const & v) const = generic;
long_double_t & operator += (int_t const & v) = generic;
long_double_t & operator -= (int_t const & v) = generic;
long_double_t & operator *= (int_t const & v) = generic;
long_double_t & operator /= (int_t const & v) = generic;
long_double_t & operator += (double_t const & v) = generic;
long_double_t & operator -= (double_t const & v) = generic;
long_double_t & operator *= (double_t const & v) = generic;
long_double_t & operator /= (double_t const & v) = generic;
long_double_t & operator += (long_double_t const & v) = generic;
long_double_t & operator -= (long_double_t const & v) = generic;
long_double_t & operator *= (long_double_t const & v) = generic;
long_double_t & operator /= (long_double_t const & v) = generic;
};
}
using numeric::int_t;
using numeric::double_t;
using numeric::long_double_t;
-- *Phil Bouchard* Founder C.: (819) 328-4743 Fornux Logo <http://www.fornux.com> On 3/11/20 7:34 AM, Phil Bouchard wrote: > > To go back to the generic template 'this', here is another useful > example that centralizes mathematical operations: > > // What the user sees: > > struct A > { > int value; > > A(A const & a) : value(a.value) > { > } > > A & operator += (A const & a) > { > value += a.value; > > return * this; > } > > A & operator -= (A const & a) > { > value -= a.value; > > return * this; > } > > A & operator *= (A const & a) > { > value *= a.value; > > return * this; > } > > A & operator /= (A const & a) > { > value /= a.value; > > return * this; > } > > A & operator = (A const & a) = generic; // the 'generic' keyword > could be used to hint the compiler of our intents > > A operator + (A const & a) const = generic; > A operator - (A const & a) const = generic; > A operator * (A const & a) const = generic; > A operator / (A const & a) const = generic; > }; > > > // Some "generic" header: > > template <typename Class> > Class & Class::operator = (Class const & c) > { > ~Class(); > > new (this) Class(c); > > return * this; > } > > template <typename Class> > Class Class::operator + (Class const & c) const > { > Class r(* this); > > r += c; > > return r; > } > > template <typename Class> > Class Class::operator - (Class const & c) const > { > Class r(* this); > > r -= c; > > return r; > } > > template <typename Class> > Class Class::operator * (Class const & c) const > { > Class r(* this); > > r *= c; > > return r; > } > > template <typename Class> > Class Class::operator / (Class const & c) const > { > Class r(* this); > > r /= c; > > return r; > } > > > -- > > *Phil Bouchard* > Founder > C.: (819) 328-4743 > > Fornux Logo <http://www.fornux.com> > > > On 3/10/20 10:00 PM, Phil Bouchard wrote: >> >> Regarding the for_each_member() functor, here is a possible >> implementation: >> >> #include <iostream> >> >> using namespace std; >> >> >> template <typename F> >> inline ostream & print(F && f, char const * n, ostream & out) >> { >> out << n; >> >> return out; >> } >> >> template <typename F> >> inline ostream & print(F && f, char const * n, char const * t, >> ostream & out) >> { >> out << n << " = " << t; >> >> return out; >> } >> >> template <typename F> >> inline ostream & print(F && f, char const * n, int const t, >> ostream & out) >> { >> out << n << " = " << t; >> >> return out; >> } >> >> template <typename F, typename T> >> inline ostream & print(F && f, char const * n, T const & t, >> ostream & out) >> { >> f.begin(n, t, out); >> typename T::template for_each_member<F, >> ostream>()(forward<F>(f), t, out); >> f.end(n, t, out); >> >> return out; >> } >> >> >> // New "pretty" header: >> >> struct pretty >> { >> size_t s; >> char c; >> >> pretty(size_t s = 0, char c = '\t') : s(s), c(c) >> { >> } >> >> ostream & indent(ostream & out) >> { >> for (size_t i = 0; i < s; ++ i) >> out << c; >> >> return out; >> } >> >> template <typename T> >> void begin(char const * n, T const & t, ostream & out) >> { >> out << n << " = " << endl; >> indent(out) << "{" << endl; >> >> ++ s; >> } >> >> template <typename T> >> void end(char const * n, T const & t, ostream & out) >> { >> -- s; >> >> indent(out) << "}"; >> } >> >> template <typename T> >> void operator () (char const * n, T const & t, size_t i, >> size_t e, ostream & out) >> { >> indent(out); >> >> print(* this, n, t, out); >> >> if (i != e - 1) >> out << ','; >> >> out << endl; >> } >> }; >> >> >> struct sql >> { >> template <typename T> >> void begin(char const * n, T const & t, ostream & out) const >> { >> out << "SELECT "; >> } >> >> template <typename T> >> void end(char const * n, T const & t, ostream & out) const >> { >> out << " FROM " << n << ";"; >> } >> >> template <typename T> >> void operator () (char const * n, T const & t, size_t i, >> size_t e, ostream & out) const >> { >> print(* this, n, out); >> >> if (i != e - 1) >> out << ", "; >> } >> }; >> >> >> // Usage example: >> >> struct A >> { >> int a = 0; >> int b = 1; >> int c = 2; >> >> // Generated by the compiler: >> template <typename F, typename ...T> >> struct for_each_member >> { >> void operator () (F && f, A const & a, T & ...t) >> { >> f("a", a.a, 0, 3, t...); >> f("b", a.b, 1, 3, t...); >> f("c", a.c, 2, 3, t...); >> } >> }; >> }; >> >> >> struct B >> { >> int d = 0; >> int e = 1; >> A f = A(); >> >> // Generated by the compiler: >> template <typename F, typename ...T> >> struct for_each_member >> { >> void operator () (F && f, B const & b, T & ...t) >> { >> f("d", b.d, 0, 3, t...); >> f("e", b.e, 1, 3, t...); >> f("f", b.f, 2, 3, t...); >> } >> }; >> }; >> >> >> int main() >> { >> B b; >> >> cout << "Pretty print:" << endl; >> print(pretty(), "b", b, cout) << endl; >> cout << endl; >> >> cout << "SQL print:" << endl; >> print(sql(), "b", b, cout) << endl; >> } >> >> >> Outputs: >> >> Pretty print: >> b = >> { >> d = 0, >> e = 1, >> f = >> { >> a = 0, >> b = 1, >> c = 2 >> } >> } >> >> SQL print: >> SELECT d, e, f FROM b; >> >> -- >> >> *Phil Bouchard* >> Founder >> C.: (819) 328-4743 >> >> Fornux Logo <http://www.fornux.com> >> >> >> On 3/10/20 1:56 PM, Phil Bouchard wrote: >>> Even better: for_each_member<> should be nested inside their >>> respective class (i.e. typename A::for_each_member<>), this way we >>> won’t pollute the global namespace at all and have a million error >>> messages when something goes wrong. >>> >>> Also we could have: >>> ...::for_each_member<> >>> ...::for_each_public_member<> >>> ...::for_each_private_member<> >>> ...::for_each_protected_member<> >>> >>> -- >>> >>> *Phil Bouchard* >>> Founder >>> C.: (819) 328-4743 <tel:(819)%20328-4743> >>> >>> Fornux Logo <http://www.fornux.com/> >>> >>> On Mar 10, 2020, at 8:50 AM, Phil Bouchard <phil_at_[hidden] >>> <mailto:phil_at_[hidden]>> wrote: >>> >>>> Here are little corrections: >>>> >>>> #include <iostream> >>>> #include <functional> >>>> >>>> using namespace std; >>>> >>>> >>>> // Compiler internal: >>>> >>>> template <typename F, typename ...T> >>>> struct for_each_member; >>>> >>>> template <typename F, typename ...T> >>>> inline void make_for_each_member(F && f, T && ...t) >>>> { >>>> for_each_member<F, T...>()(forward<F>(f), forward<T>(t)...); >>>> } >>>> >>>> >>>> // New "pretty" header: >>>> >>>> struct pretty >>>> { >>>> size_t n; >>>> >>>> pretty(size_t n = 0):n(n) {} >>>> >>>> ostream & indent(size_t n, ostream & out) >>>> { >>>> for (size_t i = 0; i < n * 4; ++ i) >>>> out << ' '; >>>> >>>> return out; >>>> } >>>> >>>> template <typename T> >>>> void operator () (T const & t, size_t i, size_t e, size_t >>>> n, ostream & out) >>>> { >>>> if (i == 0) >>>> indent(n, out) << '{' << endl; >>>> >>>> indent(n + 1, out) << t; >>>> >>>> if (i != e - 1) >>>> out << ','; >>>> >>>> out << endl; >>>> >>>> if (i == e - 1) >>>> indent(n, out) << '}'; >>>> } >>>> }; >>>> >>>> // New "print" header: >>>> >>>> template <typename T, typename F> >>>> inline ostream & T::print(F && f, ostream & out) >>>> { >>>> make_for_each_member(f, * this, cout); >>>> >>>> return out; >>>> } >>>> >>>> >>>> // Usage example: >>>> >>>> struct A >>>> { >>>> int a = 0, b = 1, c = 2; >>>> >>>> // Capabilities: >>>> template <typename F> >>>> ostream & print(F && f, ostream & out); // only a >>>> declaration needed if "print" header included >>>> }; >>>> >>>> >>>> // Generated by the compiler: >>>> >>>> template <typename F, typename ...T> >>>> struct for_each_member<F, A, T...> >>>> { >>>> void operator () (F && f, A && a, T && ...t) >>>> { >>>> f(forward<decltype(a.a)>(a.a), 0, 3, forward<T>(t)...); >>>> f(forward<decltype(a.b)>(a.b), 1, 3, forward<T>(t)...); >>>> f(forward<decltype(a.c)>(a.c), 2, 3, forward<T>(t)...); >>>> } >>>> }; >>>> >>>> >>>> int main() >>>> { >>>> A a; >>>> >>>> a.print(pretty(), cout) << endl; >>>> a.print(binary(), cout) << endl; >>>> a.print(sql(), cout) << endl; >>>> } >>>> >>>> >>>> -- >>>> >>>> *Phil Bouchard* >>>> Founder >>>> C.: (819) 328-4743 >>>> >>>> Fornux Logo <http://www.fornux.com> >>>> >>>> >>>> On 3/10/20 12:03 AM, Phil Bouchard wrote: >>>>> >>>>> Here's a prettier example, without the template template functor: >>>>> >>>>> #include <iostream> >>>>> #include <functional> >>>>> >>>>> using namespace std; >>>>> >>>>> >>>>> // Compiler internal: >>>>> >>>>> template <typename F, typename ...T> >>>>> struct for_each_member; >>>>> >>>>> template <typename F, typename ...T> >>>>> inline void make_for_each_member(F && f, T && ...t) >>>>> { >>>>> for_each_member<F, T...>()(forward<F>(f), forward<T>(t)...); >>>>> } >>>>> >>>>> >>>>> // New "pretty_print" header: >>>>> >>>>> struct pretty_print >>>>> { >>>>> size_t n; >>>>> >>>>> pretty_print(size_t n = 0):n(n) {} >>>>> >>>>> ostream & indent(size_t n, ostream & out) >>>>> { >>>>> for (size_t i = 0; i < n * 4; ++ i) >>>>> out << ' '; >>>>> >>>>> return out; >>>>> } >>>>> >>>>> template <typename T> >>>>> void operator () (T const & t, size_t i, size_t e, size_t >>>>> n, ostream & out) >>>>> { >>>>> if (i == 0) >>>>> indent(n, out) << '{' << endl; >>>>> >>>>> indent(n + 1, out) << t; >>>>> >>>>> if (i != e - 1) >>>>> out << ','; >>>>> >>>>> out << endl; >>>>> >>>>> if (i == e - 1) >>>>> indent(n, out) << '}'; >>>>> } >>>>> }; >>>>> >>>>> template <typename T> >>>>> inline ostream & T::pretty_print(size_t n, ostream & out) >>>>> { >>>>> pretty_print f(n); >>>>> >>>>> make_for_each_member<pretty_print>(f, T(), cout); >>>>> >>>>> return out; >>>>> } >>>>> >>>>> >>>>> // Usage example: >>>>> >>>>> struct A >>>>> { >>>>> int a = 0, b = 1, c = 2; >>>>> >>>>> // Capabilities: >>>>> ostream & pretty_print(size_t n, ostream & out); // only a >>>>> declaration needed if "pretty_print" header included >>>>> ostream & binary_print(ostream & out); // same here >>>>> ostream & sql_print(ostream & out); // same >>>>> }; >>>>> >>>>> >>>>> // Generated by the compiler: >>>>> >>>>> template <typename F, typename ...T> >>>>> struct for_each_member<F, A, T...> >>>>> { >>>>> void operator () (F && f, A && a, T && ...t) >>>>> { >>>>> f(forward<decltype(a.a)>(a.a), 0, 3, forward<T>(t)...); >>>>> f(forward<decltype(a.b)>(a.b), 1, 3, forward<T>(t)...); >>>>> f(forward<decltype(a.c)>(a.c), 2, 3, forward<T>(t)...); >>>>> } >>>>> }; >>>>> >>>>> >>>>> int main() >>>>> { >>>>> A a; >>>>> >>>>> a.pretty_print(0, cout) << endl; >>>>> } >>>>> >>>>> -- >>>>> >>>>> *Phil Bouchard* >>>>> Founder >>>>> C.: (819) 328-4743 >>>>> >>>>> Fornux Logo <http://www.fornux.com> >>>>> >>>>> >>>>> On 3/9/20 8:44 PM, Phil Bouchard wrote: >>>>>> >>>>>> Here is a clean usage example: >>>>>> >>>>>> #include <iostream> >>>>>> #include <functional> >>>>>> >>>>>> using namespace std; >>>>>> >>>>>> >>>>>> // Compiler internal: >>>>>> >>>>>> template <template <typename> class F, typename ...T> // note the >>>>>> usage of the necessary template template parameter >>>>>> struct for_each_member; >>>>>> >>>>>> template <template <typename> class F, typename ...T> >>>>>> inline void make_for_each_member(T && ...t) >>>>>> { >>>>>> for_each_member<F, T...>()(forward<T>(t)...); >>>>>> } >>>>>> >>>>>> >>>>>> // New "pretty_print" header: >>>>>> >>>>>> template <typename T> >>>>>> struct pretty_print >>>>>> { >>>>>> ostream & indent(size_t n, ostream & out) >>>>>> { >>>>>> for (size_t i = 0; i < n * 4; ++ i) >>>>>> out << ' '; >>>>>> >>>>>> return out; >>>>>> } >>>>>> >>>>>> void operator () (T const & t, size_t i, size_t e, size_t >>>>>> n, ostream & out) >>>>>> { >>>>>> if (i == 0) >>>>>> indent(n, out) << '{' << endl; >>>>>> >>>>>> indent(n + 1, out) << t; >>>>>> >>>>>> if (i != e - 1) >>>>>> out << ','; >>>>>> >>>>>> out << endl; >>>>>> >>>>>> if (i == e - 1) >>>>>> indent(n, out) << '}'; >>>>>> } >>>>>> }; >>>>>> >>>>>> template <typename T> >>>>>> inline ostream & T::pretty_print(ostream & out) >>>>>> { >>>>>> size_t indent = 0; >>>>>> >>>>>> make_for_each_member<pretty_print>(T(), indent, cout); >>>>>> >>>>>> return out; >>>>>> } >>>>>> >>>>>> >>>>>> // Usage example (what the user will only see): >>>>>> >>>>>> struct A >>>>>> { >>>>>> int a = 0, b = 1, c = 2; >>>>>> >>>>>> ostream & pretty_print(ostream & out); // only a declaration >>>>>> needed if "pretty_print" header included >>>>>> }; >>>>>> >>>>>> >>>>>> // Generated by the compiler: >>>>>> >>>>>> template <template <typename> class F, typename ...T> >>>>>> struct for_each_member<F, A, T...> >>>>>> { >>>>>> void operator () (A && a, T && ...t) >>>>>> { >>>>>> F<decltype(a.a)>()(forward<decltype(a.a)>(a.a), 0, 3, >>>>>> forward<T>(t)...); >>>>>> F<decltype(a.b)>()(forward<decltype(a.b)>(a.b), 1, 3, >>>>>> forward<T>(t)...); >>>>>> F<decltype(a.c)>()(forward<decltype(a.c)>(a.c), 2, 3, >>>>>> forward<T>(t)...); >>>>>> } >>>>>> }; >>>>>> >>>>>> >>>>>> int main() >>>>>> { >>>>>> A a; >>>>>> >>>>>> a.pretty_print(cout) << endl; >>>>>> } >>>>>> >>>>>> >>>>>> Other applications of for_each_member() can be: >>>>>> >>>>>> - comparisons, >>>>>> >>>>>> - changing properties of filtered mutable member variables, >>>>>> >>>>>> - generic debug functions changed on-the-fly at one place only, >>>>>> >>>>>> - easily apply textual and binary I/O operations to huge structures, >>>>>> >>>>>> - easily apply database operations to huge structures, >>>>>> >>>>>> - automate the mapping of structures to a user-interface generator, >>>>>> >>>>>> - ... >>>>>> >>>>>> >>>>>> -- >>>>>> >>>>>> *Phil Bouchard* >>>>>> Founder >>>>>> C.: (819) 328-4743 >>>>>> >>>>>> Fornux Logo <http://www.fornux.com> >>>>>> >>>>>> >>>>>> On 3/9/20 10:56 AM, Phil Bouchard wrote: >>>>>>> ... Also we could limit generic ‘this’ overloads to specific >>>>>>> namespaces: >>>>>>> >>>>>>> template <typename Class> >>>>>>> ostream & boost::detail::Class::operator << (ostream & out) >>>>>>> { ... } >>>>>>> >>>>>>> -- >>>>>>> >>>>>>> *Phil Bouchard* >>>>>>> Founder >>>>>>> C.: (819) 328-4743 <tel:(819)%20328-4743> >>>>>>> >>>>>>> Fornux Logo <http://www.fornux.com/> >>>>>>> >>>>>>> On Mar 8, 2020, at 7:36 PM, Phil Bouchard <phil_at_[hidden] >>>>>>> <mailto:phil_at_[hidden]>> wrote: >>>>>>> >>>>>>>> ... And only the classes with the proper declarations would >>>>>>>> take advantage of the generic template 'this': >>>>>>>> >>>>>>>> >>>>>>>> -- >>>>>>>> >>>>>>>> *Phil Bouchard* >>>>>>>> Founder >>>>>>>> C.: (819) 328-4743 >>>>>>>> >>>>>>>> Fornux Logo <http://www.fornux.com> >>>>>>>> >>>>>>>> >>>>>>>> On 3/8/20 7:34 PM, Phil Bouchard wrote: >>>>>>>>> >>>>>>>>> What I have in mind is to clean up the dispatch fiasco that is >>>>>>>>> done with either the constructors or the cast operator right >>>>>>>>> now. Conversions, comparisons, ... should be simplified as >>>>>>>>> well. For example: >>>>>>>>> >>>>>>>>> struct X >>>>>>>>> >>>>>>>>> { >>>>>>>>> >>>>>>>>> int value; >>>>>>>>> >>>>>>>>> >>>>>>>>> template <typename T> >>>>>>>>> >>>>>>>>> X(T const & T); >>>>>>>>> >>>>>>>>> template <typename T> >>>>>>>>> >>>>>>>>> operator T (); >>>>>>>>> >>>>>>>>> }; >>>>>>>>> >>>>>>>>> struct Y >>>>>>>>> >>>>>>>>> { >>>>>>>>> >>>>>>>>> int value; >>>>>>>>> >>>>>>>>> >>>>>>>>> template <typename T> >>>>>>>>> >>>>>>>>> Y(T const & T); >>>>>>>>> >>>>>>>>> template <typename T> >>>>>>>>> >>>>>>>>> operator T (); >>>>>>>>> >>>>>>>>> }; >>>>>>>>> >>>>>>>>> template <typename Class, typename T> >>>>>>>>> >>>>>>>>> inline Class::operator T () { return T(* this); } // >>>>>>>>> generic constructor wrapper >>>>>>>>> >>>>>>>>> template <typename Class, typename T> >>>>>>>>> >>>>>>>>> inline Class::Class(T const &t) { value = t.value; } // >>>>>>>>> cast operation really done here >>>>>>>>> >>>>>>>>> >>>>>>>>> And normal specializations here: >>>>>>>>> >>>>>>>>> template <typename T> >>>>>>>>> >>>>>>>>> inline X::X(T const &t) { value = t.value; } // >>>>>>>>> specialized cast operation done here >>>>>>>>> >>>>>>>>> >>>>>>>>> Also if we had a way to iterate all members (which would be >>>>>>>>> another important proposal) then we could also have a generic >>>>>>>>> "operator <<" as well: >>>>>>>>> >>>>>>>>> template <typename Class> >>>>>>>>> >>>>>>>>> ostream & Class::operator << (ostream & out) >>>>>>>>> >>>>>>>>> { >>>>>>>>> >>>>>>>>> for (member_iterator<Class> i = >>>>>>>>> member_iterator<Class>::begin(); i != >>>>>>>>> member_iterator<Class>::end(); ++ i) >>>>>>>>> >>>>>>>>> { >>>>>>>>> >>>>>>>>> if (i != member_iterator<Class>::begin()) >>>>>>>>> >>>>>>>>> out << ", "; >>>>>>>>> >>>>>>>>> out << this->*i; >>>>>>>>> >>>>>>>>> } >>>>>>>>> >>>>>>>>> return out; >>>>>>>>> >>>>>>>>> } >>>>>>>>> >>>>>>>>> The aforementioned should also remove the need for these >>>>>>>>> global friend function overloads. >>>>>>>>> >>>>>>>>> >>>>>>>>> -- >>>>>>>>> >>>>>>>>> *Phil Bouchard* >>>>>>>>> Founder >>>>>>>>> C.: (819) 328-4743 >>>>>>>>> >>>>>>>>> Fornux Logo <http://www.fornux.com> >>>>>>>>> >>>>>>>>> >>>>>>>>> On 3/8/20 6:03 PM, Jake Arkinstall wrote: >>>>>>>>>> For me, this approach has some merits, but this particular >>>>>>>>>> example is something that, to me, makes much more sense as a >>>>>>>>>> free function. >>>>>>>>>> >>>>>>>>>> Do you have further examples? >>>>>>>>>> >>>>>>>>>> On Sun, 8 Mar 2020, 21:55 Phil Bouchard via Std-Proposals, >>>>>>>>>> <std-proposals_at_[hidden] >>>>>>>>>> <mailto:std-proposals_at_[hidden]>> wrote: >>>>>>>>>> >>>>>>>>>> Well I believe a proposal should be open for debate, just >>>>>>>>>> like a thesis. >>>>>>>>>> >>>>>>>>>> We both agree these overloads should be simplified but we >>>>>>>>>> disagree on the syntax. >>>>>>>>>> >>>>>>>>>> I saw the recursive lambda thing and I think I already >>>>>>>>>> talked to you before regarding CV overloads but we were >>>>>>>>>> proposing the following syntax: >>>>>>>>>> >>>>>>>>>> struct A >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> template <bool BC> >>>>>>>>>> >>>>>>>>>> void foo() bool<BC> >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> }; >>>>>>>>>> >>>>>>>>>> And regarding the this generic overloading I still >>>>>>>>>> believe the following syntax is cleaner: >>>>>>>>>> >>>>>>>>>> struct A >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> template <typename T> >>>>>>>>>> >>>>>>>>>> bool compare(T const &); >>>>>>>>>> >>>>>>>>>> }; >>>>>>>>>> >>>>>>>>>> template <typename C, typename T> >>>>>>>>>> >>>>>>>>>> void C::compare(C const &) >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> ... >>>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> Because with your syntax I could technically reassign "self": >>>>>>>>>> >>>>>>>>>> struct A >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> template <typename C, typename T> >>>>>>>>>> >>>>>>>>>> bool compare(this C & c, T const &); >>>>>>>>>> >>>>>>>>>> }; >>>>>>>>>> >>>>>>>>>> template <typename C, typename T> >>>>>>>>>> >>>>>>>>>> bool C::compare(this C & c, T const &) // redundant C >>>>>>>>>> here >>>>>>>>>> >>>>>>>>>> { >>>>>>>>>> >>>>>>>>>> static C sc = C(); >>>>>>>>>> >>>>>>>>>> c = sc; // in theory we could do this unless you >>>>>>>>>> patch the compilers with a new error for that specific case >>>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> >>>>>>>>>> *Phil Bouchard* >>>>>>>>>> Founder >>>>>>>>>> C.: (819) 328-4743 >>>>>>>>>> >>>>>>>>>> Fornux Logo <http://www.fornux.com> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> On 3/8/20 5:37 AM, Gašper Ažman wrote: >>>>>>>>>>> I meant that you should consider the incremental value >>>>>>>>>>> of your proposal over p0847, which is on track for c++23 >>>>>>>>>>> unless serious issues crop up >>>>>>>>>>> >>>>>>>>>>> On Sat, Mar 7, 2020, 19:04 Phil Bouchard >>>>>>>>>>> <phil_at_[hidden] <mailto:phil_at_[hidden]>> wrote: >>>>>>>>>>> >>>>>>>>>>> The syntaxes are way different: >>>>>>>>>>> >>>>>>>>>>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0847r4.html >>>>>>>>>>> >>>>>>>>>>> In your case the compiler will have to change all of >>>>>>>>>>> its rules for the number of parameters "operator" >>>>>>>>>>> overloads. For example: >>>>>>>>>>> >>>>>>>>>>> struct A >>>>>>>>>>> >>>>>>>>>>> { >>>>>>>>>>> >>>>>>>>>>> int value; >>>>>>>>>>> >>>>>>>>>>> ... >>>>>>>>>>> >>>>>>>>>>> template <typename Self> >>>>>>>>>>> >>>>>>>>>>> bool operator < (this Self && self, A const >>>>>>>>>>> & a) // 2 parameters... ok >>>>>>>>>>> >>>>>>>>>>> { >>>>>>>>>>> >>>>>>>>>>> return self.value < a.value; >>>>>>>>>>> >>>>>>>>>>> } >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> bool operator < (A const & a) // 1 >>>>>>>>>>> parameter... ok >>>>>>>>>>> >>>>>>>>>>> { >>>>>>>>>>> >>>>>>>>>>> return value < a.value; >>>>>>>>>>> >>>>>>>>>>> } >>>>>>>>>>> >>>>>>>>>>> }; >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> >>>>>>>>>>> *Phil Bouchard* >>>>>>>>>>> Founder >>>>>>>>>>> C.: (819) 328-4743 >>>>>>>>>>> >>>>>>>>>>> Fornux Logo <http://www.fornux.com> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On 3/7/20 1:35 PM, Gašper Ažman wrote: >>>>>>>>>>>> P0847 >>>>>>>>>>>> >>>>>>>>>>>> On Sat, Mar 7, 2020, 18:33 Phil Bouchard via >>>>>>>>>>>> Std-Proposals <std-proposals_at_[hidden] >>>>>>>>>>>> <mailto:std-proposals_at_[hidden]>> wrote: >>>>>>>>>>>> >>>>>>>>>>>> Alright, I'm pretty sure this is not >>>>>>>>>>>> implemented yet. Suppose you have: >>>>>>>>>>>> >>>>>>>>>>>> struct A >>>>>>>>>>>> >>>>>>>>>>>> { >>>>>>>>>>>> >>>>>>>>>>>> int value; >>>>>>>>>>>> >>>>>>>>>>>> ... >>>>>>>>>>>> >>>>>>>>>>>> template <typename T> >>>>>>>>>>>> >>>>>>>>>>>> int compare(T const & t) const; >>>>>>>>>>>> >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> struct B >>>>>>>>>>>> >>>>>>>>>>>> { >>>>>>>>>>>> >>>>>>>>>>>> int value; >>>>>>>>>>>> >>>>>>>>>>>> ... >>>>>>>>>>>> >>>>>>>>>>>> template <typename T> >>>>>>>>>>>> >>>>>>>>>>>> int compare(T const & t) const; >>>>>>>>>>>> >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> Then a generic way to define the same >>>>>>>>>>>> functionality for all classes would be to have >>>>>>>>>>>> a "template 'this'": >>>>>>>>>>>> >>>>>>>>>>>> template <typename C, typename T> >>>>>>>>>>>> >>>>>>>>>>>> inline int C::compare(T const & t) const >>>>>>>>>>>> >>>>>>>>>>>> { >>>>>>>>>>>> >>>>>>>>>>>> return value == t.value ? 0 : value < t.value ? >>>>>>>>>>>> -1 : 1; >>>>>>>>>>>> >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> (Please include my email address in your replies) >>>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> -- >>>>>>>>>>>> >>>>>>>>>>>> *Phil Bouchard* >>>>>>>>>>>> Founder >>>>>>>>>>>> C.: (819) 328-4743 >>>>>>>>>>>> >>>>>>>>>>>> Fornux Logo <http://www.fornux.com> >>>>>>>>>>>> -- >>>>>>>>>>>> Std-Proposals mailing list >>>>>>>>>>>> Std-Proposals_at_[hidden] >>>>>>>>>>>> <mailto:Std-Proposals_at_[hidden]> >>>>>>>>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals >>>>>>>>>>>> >>>>>>>>>> -- >>>>>>>>>> Std-Proposals mailing list >>>>>>>>>> Std-Proposals_at_[hidden] >>>>>>>>>> <mailto:Std-Proposals_at_[hidden]> >>>>>>>>>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals >>>>>>>>>>
Received on 2020-03-12 16:27:14