Issue with temporaries and operator overloading - c++

I am working on operator overloading to generate lazy object evaluation. For this reason class at operator+() doesn’t do more than storing reference of passed classes to evaluate later.
struct Base
{
virtual void expensive_func()
{
throw "cant use this";
};
Composer operator+(int i)
{
return Composer(*this, i);
}
}
struct Composer:public Base
{
Base& refBase;
int increment;
virtual void expensive_func()
{
heavy_work();
};
Composer(Base& a,int inc):
refBase(a),increment(inc)
{
}
}
struct D:public Base
{
...
}
And than problem arase
D a;
auto b = a + 2;
auto c = b + 3;
auto e = a + 3 + 4;
a.expensive_func(); //fine
b.expensive_func(); //fine
c.expensive_func(); //fine
e.expensive_func(); //segfault
On solution is to prevent such manoeuvres with
operator+(const Coposer&&,int) = delete;
But this just prevents doing something of what I would like to do
Full code: - I am building with gcc/g++ 4.8
#include <iostream>
#include <string.h>
#include <vector>
#include <algorithm>
#include <memory>
namespace Intervals
{
template <typename T> struct ContainerMove; //forward declaration
template <typename T>
struct ContainerBase {
typedef T mT;
virtual T GetInterval (const T& val)
{
throw; //overload this
}
T Integrate(const T& start = T(0))
{
T r(0);
T next(start);
while(1)
{
T i = GetInterval(next);
if(i<0) //less that 0 is considered end
{
return r;
}
r+=i;
next=i;
}
}
ContainerMove<T> operator +(const T& left);
ContainerMove<T> operator -(const T& left);
virtual ~ContainerBase(){};
};
//lazy container of ContainerBase
template <typename T>
struct ContainerMove:public ContainerBase<T>
{
typedef ContainerBase<T> mConatinerBase;
const T mOffset;
mConatinerBase& mIntervalSet;
ContainerMove(mConatinerBase& intervalset, const T& offset)
:mOffset(offset),mIntervalSet(intervalset)
{}
virtual T GetInterval (const T& val)
{
auto i = mIntervalSet.GetInterval(val-mOffset);
if(i < 0)
{
return T(-1000);
}
return T(i+mOffset);
}
};
template <typename T>
ContainerMove<T> ContainerBase<T>::operator +(const ContainerBase<T>::mT& a)
{
return ContainerMove<T>(*this,a);
}
template <typename T>
ContainerMove<T> ContainerBase<T>::operator -(const ContainerBase<T>::mT& a)
{
return ContainerMove<T>(*this,-a);
}
/*
template <typename T>
ContainerMove<T> operator +(const ContainerMove<T>&& , const typename ContainerBase<T>::mT&) = delete;
template <typename T>
ContainerMove<T> operator -(const ContainerMove<T>&& , const typename ContainerBase<T>::mT&) = delete;
*/
template <class T>
struct Container:public ContainerBase<T>
{
typedef Container<T> mThisType;
typedef T mT;
typedef std::vector<T> SortedContainer_t;
SortedContainer_t mContainer;
template<class ForwardIter>
Container(ForwardIter begin,ForwardIter end)
:mContainer(begin,end)
{
}
T GetInterval (const T& val)
{
auto r = std::upper_bound(mContainer.begin(), mContainer.end(),val);
if (r == mContainer.end())
{
return T(-1000); //just as exeample <0 is ivalid value
}
return *r;
}
};
}
int main()
{
typedef float T;
typedef Intervals::Container<T> ContainerType;
std::vector<T> v,u;
const int N = 10;
for(int i=0;i<N;++i)
{
v.push_back(T(i));
}
auto c = ContainerType(v.begin(),v.end());
auto d=c+T(1);
auto e=c+T(2)+T(3); //this yelds segmentation after e.Integrate()
//std::cout << c.Integrate() << std::endl;
//std::cout << d.Integrate() << std::endl;
std::cout << e.Integrate() << std::endl; //crash here
return 0;
}

Related

Skip intermediate classes in hierarchy inheritance with boost::serialization

Context: I have a tree-like structure representing a AST of Expr that I want to serialize using boost::serialization. The main issue is that all classes have non default constructors and const children. To overcome this issue, I followed the doc and overloaded load_construct_data and save_construct_data (which end up doing all the work).
My question is about the Mul class within the code. To factorize code, I developed a template class Op2 that is used to define operators such as Add or Mul (only Mul is shown here) through CRTP on these classes. In Mul::serialize, I directly register Expr as base class of Muland completely skip Op2. The code works, valgrind is happy, but is it correct ? Or does boost::serialization require to ave the complete class hierarchy ?
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
//forward declaration of my structs
struct Expr;
struct Mul;
struct Int;
//forward declarations of custom boost functions to friend them in the class
namespace b_ser = boost::serialization;
namespace boost {
namespace serialization {
template <class Archive>
void load_construct_data(Archive &ar, Mul *e, const unsigned int);
template <class Archive>
void save_construct_data(Archive &ar, const Mul *a, const unsigned int);
template <class Archive>
void load_construct_data(Archive &ar, Int *e, const unsigned int);
template <class Archive>
void save_construct_data(Archive &ar, const Int *a, const unsigned int);
} // namespace serialization
} // namespace boost
//memory manager
std::vector<std::unique_ptr<Expr>> pool;
// AST
struct Expr {
virtual ~Expr() {}
virtual std::vector<Expr const *> children() const = 0;
virtual std::string identity() const = 0;
void print(int p) const {
std::cout << std::setw(p) << ' ';
std::cout << identity() << "\n";
for (auto a_kid : children()) {
a_kid->print(p + 2);
}
}
void self_register() const {
if (std::find_if(pool.begin(), pool.end(), [this](auto const &stored_ptr) {
return this == stored_ptr.get();
}) == pool.end()) {
pool.push_back(std::unique_ptr<Expr>(const_cast<Expr *>(this)));
}
for (auto ptr : children()) {
ptr->self_register();
}
}
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {}
};
struct Int : Expr {
int const n;
std::vector<Expr const *> children() const override { return {}; }
std::string identity() const override {
return "Int[" + std::to_string(n) + "]#";
}
Int(int nn) : n(nn) {}
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &boost::serialization::base_object<Expr>(*this);
}
template <class Archive>
friend void b_ser::save_construct_data(Archive &ar, const Int *i,
const unsigned int) {
ar << i->n;
}
template <class Archive>
friend void b_ser::load_construct_data(Archive &ar, Int *i,
const unsigned int) {
int n;
ar >> n;
::new (i) Int(n);
}
};
template <class T> struct Op2 : Expr {
std::vector<Expr const *> children() const override { return {l, r}; }
std::string identity() const override { return T::message; }
Op2(Expr const *ll, Expr const *rr) : l(ll), r(rr) {}
protected:
Expr const *l;
Expr const *r;
};
struct Mul : Op2<Mul> {
using Op2::Op2;
static auto const constexpr message = "Mul";
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive &ar, const unsigned int version) {
ar &boost::serialization::base_object<Expr>(*this);
}
template <class Archive>
friend void b_ser::save_construct_data(Archive &ar, const Mul *a,
const unsigned int) {
ar << a->l;
ar << a->r;
}
template <class Archive>
friend void b_ser::load_construct_data(Archive &ar, Mul *e,
const unsigned int) {
Expr *l, *r;
ar >> l;
ar >> r;
::new (e) Mul(l, r);
e->self_register();
}
};
template <class T, class... Args> T *store(Args... args) {
auto to_store = std::make_unique<T>(std::forward<Args>(args)...);
auto raw_ptr = to_store.get();
pool.push_back(std::move(to_store));
return raw_ptr;
}
BOOST_CLASS_EXPORT(Expr)
BOOST_CLASS_EXPORT(Int)
BOOST_CLASS_EXPORT(Mul)
int main(int argc, char *argv[]) {
{
auto deux = store<Int>(2);
auto trois = store<Int>(3);
auto m_23 = store<Mul>(trois, deux);
auto quatre = store<Int>(4);
auto root = store<Mul>(m_23, quatre);
Expr *e_root = root;
root->print(2);
std::ofstream of("arxiv");
boost::archive::text_oarchive oa(of);
oa << e_root;
}
std::cout << "==================="
<< "\n";
{
std::ifstream isf("arxiv");
boost::archive::text_iarchive is(isf);
Expr *expr;
is >> expr;
expr->print(2);
}
return 0;
}
Firstly, I conclude you must be using MSVC since your code is not valid standard C++.
Fixing things shows it appears to work properly on Clang and GCC.
Enabling AddressSanitizer quickly reveals errors that I /believe/ might originate in the singleton code deep inside Boost Serialization. I'll ignore it for now.
Due to those errors, I looked at this a long time, trying to see whether the code was to blame.
While doing so, I found that many things could be made a lot simpler.
you can do without construct-data if you just add private default constructors for serialization purposes.
The important thing about your classes are the invariants, and it's easy to prove that invariants are kept across deserialization this way.
you can do without the subclasses for each binary operator, because they add literally no behaviour. Consider providing the message constant out-of-band
instead of making a vector<unique_ptr> you can use a pointer container that implicitly owns its elements. This makes e.g. looking up equivalent pointers a lot easier:
namespace memory_management {
struct address_less {
bool operator()(Expr const& a, Expr const& b) const { return &a < &b; }
};
static boost::ptr_set<Expr, address_less> pool;
}
void Expr::self_register() { memory_management::pool.insert(this); }
All in all things are much shorter:
// AST
struct Expr {
virtual ~Expr() = default;
virtual std::vector<Expr const *> children() const { return {}; }
virtual std::string identity() const = 0;
void print(int p) const {
std::cout << std::setw(p) << ' ';
std::cout << identity() << "\n";
for (auto a_kid : children()) {
a_kid->print(p + 2);
}
}
protected:
Expr() { self_register(); }
private:
void self_register();
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned) {}
};
namespace memory_management {
struct address_less {
bool operator()(Expr const& a, Expr const& b) const { return &a < &b; }
};
static boost::ptr_set<Expr, address_less> pool;
}
void ::Expr::self_register() { memory_management::pool.insert(this); }
struct Int : Expr {
std::string identity() const override { return "Int[" + std::to_string(n) + "]#"; }
Int(int nn) : n(nn) {}
private:
int const n = 0;
friend class boost::serialization::access;
Int() = default;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & boost::serialization::base_object<Expr>(*this)
& const_cast<int&>(n);
}
};
namespace Tags {
struct Mul;
struct Div;
struct Plus;
struct Minus;
template <typename T> constexpr char const* const message = "Unknown";
template <> constexpr char const* const message<Mul> = "Mul";
template <> constexpr char const* const message<Div> = "Div";
template <> constexpr char const* const message<Plus> = "Plus";
template <> constexpr char const* const message<Minus> = "Minus";
}
template <class T> struct Op2 : Expr {
std::vector<Expr const *> children() const override { return { l, r }; }
std::string identity() const override { return Tags::message<T>; }
Op2(Expr *ll, Expr *rr) : l(ll), r(rr) {}
protected:
friend class boost::serialization::access;
Op2() = default;
Expr *l = nullptr;
Expr *r = nullptr;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & boost::serialization::base_object<Expr>(*this)
& l & r;
}
};
using Mul = Op2<Tags::Mul>;
using Div = Op2<Tags::Div>;
using Plus = Op2<Tags::Plus>;
using Minus = Op2<Tags::Minus>;
Bonus: A DSL For AST Building
I thought it would be nicer to be able to say:
Expr const* root((as_expr(3) * 2) + 5 + (as_expr(7) / 25));
So, let's do that:
namespace builder {
struct Atom {
Atom(Expr* expr) : expr(expr) {}
Atom(int i) : expr(new Int(i)) {}
Expr* expr;
explicit operator Expr const*() const { return expr; }
};
template <typename T>
Atom as_expr(T&& v) { return std::forward<T>(v); }
Atom operator+(Atom a, Atom b) { return new Plus(a.expr, b.expr); }
Atom operator-(Atom a, Atom b) { return new Minus(a.expr, b.expr); }
Atom operator*(Atom a, Atom b) { return new Mul(a.expr, b.expr); }
Atom operator/(Atom a, Atom b) { return new Div(a.expr, b.expr); }
}
LIVE DEMO
Live On Coliru
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/ptr_container/ptr_set.hpp>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <vector>
// AST
struct Expr {
virtual ~Expr() = default;
virtual std::vector<Expr const *> children() const { return {}; }
virtual std::string identity() const = 0;
void print(int p) const {
std::cout << std::setw(p) << ' ';
std::cout << identity() << "\n";
for (auto a_kid : children()) {
a_kid->print(p + 2);
}
}
protected:
Expr() { self_register(); }
private:
void self_register();
friend class boost::serialization::access;
template <class Archive> void serialize(Archive &, unsigned) {}
};
namespace memory_management {
struct address_less {
bool operator()(Expr const& a, Expr const& b) const { return &a < &b; }
};
static boost::ptr_set<Expr, address_less> pool;
}
void ::Expr::self_register() { memory_management::pool.insert(this); }
struct Int : Expr {
std::string identity() const override { return "Int[" + std::to_string(n) + "]#"; }
Int(int nn) : n(nn) {}
private:
int const n = 0;
friend class boost::serialization::access;
Int() = default;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & boost::serialization::base_object<Expr>(*this)
& const_cast<int&>(n);
}
};
namespace Tags {
struct Mul;
struct Div;
struct Plus;
struct Minus;
template <typename T> constexpr char const* const message = "Unknown";
template <> constexpr char const* const message<Mul> = "Mul";
template <> constexpr char const* const message<Div> = "Div";
template <> constexpr char const* const message<Plus> = "Plus";
template <> constexpr char const* const message<Minus> = "Minus";
}
template <class T> struct Op2 : Expr {
std::vector<Expr const *> children() const override { return { l, r }; }
std::string identity() const override { return Tags::message<T>; }
Op2(Expr *ll, Expr *rr) : l(ll), r(rr) {}
protected:
friend class boost::serialization::access;
Op2() = default;
Expr *l = nullptr;
Expr *r = nullptr;
template <class Archive> void serialize(Archive &ar, unsigned) {
ar & boost::serialization::base_object<Expr>(*this)
& l & r;
}
};
using Mul = Op2<Tags::Mul>;
using Div = Op2<Tags::Div>;
using Plus = Op2<Tags::Plus>;
using Minus = Op2<Tags::Minus>;
namespace builder {
struct Atom {
Atom(Expr* expr) :expr(expr){}
Atom(int i) :expr(new Int(i)){}
Expr* expr;
explicit operator Expr const*() const { return expr; }
};
template <typename T>
Atom as_expr(T&& v) { return std::forward<T>(v); }
Atom operator+(Atom a, Atom b) { return new Plus(a.expr, b.expr); }
Atom operator-(Atom a, Atom b) { return new Minus(a.expr, b.expr); }
Atom operator*(Atom a, Atom b) { return new Mul(a.expr, b.expr); }
Atom operator/(Atom a, Atom b) { return new Div(a.expr, b.expr); }
}
BOOST_CLASS_EXPORT(Expr)
BOOST_CLASS_EXPORT(Int)
BOOST_CLASS_EXPORT(Mul)
BOOST_CLASS_EXPORT(Div)
BOOST_CLASS_EXPORT(Plus)
BOOST_CLASS_EXPORT(Minus)
int main() {
std::cout << std::unitbuf;
{
using builder::as_expr;
Expr const* root((as_expr(3) * 2) + 5 + (as_expr(7) / 25));
root->print(2);
std::ofstream of("arxiv");
boost::archive::text_oarchive oa(of);
oa << root;
}
std::cout << "===================\n";
{
std::ifstream isf("arxiv");
boost::archive::text_iarchive is(isf);
Expr *expr = nullptr;
is >> expr;
expr->print(2);
}
memory_management::pool.clear(); // no memory leaks
}
Prints
Plus
Plus
Mul
Int[3]#
Int[2]#
Int[5]#
Div
Int[7]#
Int[25]#
===================
Plus
Plus
Mul
Int[3]#
Int[2]#
Int[5]#
Div
Int[7]#
Int[25]#

expression templates - bad_alloc

i am currently working on a c++ project and now i am stuck already for a while. It's about delayed evaluation with expression templates and (for me at least) a strange bad_alloc.
If you try the code below, you'll notice runtime error bad_alloc due to the very last addition b+c. So thats the point where the delayed evaluation is done. Furthermore the code below compiles and runs fine if you remove the references of the members of "Expression" (left,right). But i need references there, due to performance, etc. . However i also dont see, why i cant use references there.
I've already spent a lot of time with it. Please let me know if somebody can help me.
Best Regards.
#include <iostream>
#include <vector>
template<typename value_t, typename left_t, typename right_t, typename op_t>
class Expression
{
public:
typedef value_t value_type;
explicit Expression(const left_t &left,
const right_t &right,
const op_t &op) :
left(left),
right(right),
op(op)
{
}
value_t operator [](const size_t &i) const
{
return op(left[i],right[i]);
}
size_t size() const { return left.size();}
private:
const left_t &left;
const right_t &right;
//const left_t left;
//const right_t right;
const op_t &op;
};
template<class left_t,
class right_t,
class value_t = typename left_t::value_type,
class op_t = std::plus<value_t>>
const Expression<value_t, left_t, right_t, op_t> operator +(const left_t &left,
const right_t &right)
{
return Expression<value_t,left_t,right_t,op_t>(left, right, op_t());
}
template<typename value_t, typename data_t = std::vector<value_t>>
class Vector : public data_t
{
public:
typedef value_t value_type;
using data_t::size;
Vector(const std::initializer_list<value_t> &list) :
data_t(list)
{
}
Vector(const size_t &n) :
data_t(n)
{
}
Vector(const Vector &v) :
data_t(v)
{
}
template<typename left_t, typename right_t, typename op_t>
Vector(const Expression<value_t,left_t,right_t,op_t> &v) :
data_t(v.size())
{
operator =(v);
}
template<typename vec_t>
Vector(const vec_t &v) :
data_t(v.size())
{
operator =(v);
}
template<typename vec_t>
Vector &operator =(const vec_t &v)
{
for(size_t i = 0; i < data_t::size(); ++i)
data_t::operator [](i) = v[i];
return (*this);
}
friend std::ostream &operator <<(std::ostream &os, const Vector &v)
{
if(v.size())
os << v[0];
for(size_t i = 1; i < v.size(); ++i)
os << " " << v[i];
return os;
}
};
int main()
{
Vector<double> a{0,1,2};
auto b = a+a+a;
auto c = a;
std::cout << a+a+a+a << std::endl;
std::cout << b+c << std::endl; // gives bad_alloc
return 0;
}
"But i need references there, due to performance, etc."
Prove it.
In expression templates, all¹ the information should be compile-time.
You can see my example here for a simple expression template:
// we have lazy placeholder types:
template <int N> struct placeholder {};
placeholder<1> _1;
placeholder<2> _2;
placeholder<3> _3;
// note that every type here is stateless, and acts just like a more
// complicated placeholder.
// We can have expressions, like binary addition:
template <typename L, typename R> struct addition { };
template <typename L, typename R> struct multiplication { };
// here is the "factory" for our expression template:
template <typename L, typename R> addition<L,R> operator+(L const&, R const&) { return {}; }
template <typename L, typename R> multiplication<L,R> operator*(L const&, R const&) { return {}; }
///////////////////////////////////////////////
// To evaluate/interpret the expressions, we have to define "evaluation" for each type of placeholder:
template <typename Ctx, int N>
auto eval(Ctx& ctx, placeholder<N>) { return ctx.arg(N); }
template <typename Ctx, typename L, typename R>
auto eval(Ctx& ctx, addition<L, R>) { return eval(ctx, L{}) + eval(ctx, R{}); }
template <typename Ctx, typename L, typename R>
auto eval(Ctx& ctx, multiplication<L, R>) { return eval(ctx, L{}) * eval(ctx, R{}); }
///////////////////////////////////////////////
// A simple real-life context would contain the arguments:
#include <vector>
struct Context {
std::vector<double> _args;
// define the operation to get an argument from this context:
double arg(int i) const { return _args.at(i-1); }
};
#include <iostream>
int main() {
auto foo = _1 + _2 + _3;
Context ctx { { 3, 10, -4 } };
std::cout << "foo: " << eval(ctx, foo) << "\n";
std::cout << "_1 + _2 * _3: " << eval(ctx, _1 + _2 * _3) << "\n";
}
So what you need is a literal type that holds a reference to the associated value, and defer all other evaluation to evaluation time.
I might prefer to add the size() operation as a free function, so that you don't have to encumber all the expression types with it (Separation Of Concerns).
¹ nearly, nl. except when encoding literals
Proof Of Concept
Using the strategy outlined:
Live On Coliru
#include <iostream>
#include <tuple>
namespace ETL {
template <typename T>
struct Literal {
T value;
T get() const { return value; }
};
/*
*template <typename T>
* static inline std::ostream& operator<<(std::ostream& os, ETL::Literal<T> const& lit) {
* return os << __PRETTY_FUNCTION__ << "\n actual: lit.value = " << lit.value;
* }
*/
template <class L, class R, class Op>
struct BinaryExpr : std::tuple<L, R, Op> { // tuple optimizes for empty element types
BinaryExpr(L l, R r, Op op)
: std::tuple<L, R, Op> { l, r, op }
{}
L const& get_lhs() const { return std::get<0>(*this); }
R const& get_rhs() const { return std::get<1>(*this); }
Op const& get_op() const { return std::get<2>(*this); }
};
template <class L, class R, class Op> auto cured(BinaryExpr<L,R,Op> _) { return _; }
template <class T> auto cured(Literal<T> l) { return std::move(l); }
template <class T> Literal<T> cured(T&& v) { return {std::forward<T>(v)}; }
template <class Op, class L, class R>
BinaryExpr<L, R, Op> make_binexpr(L&& l, R&& r) { return { std::forward<L>(l), std::forward<R>(r), Op{} }; }
template <class L, class R> auto operator +(L&& l, R&& r)
{ return make_binexpr<std::plus<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator -(L&& l, R&& r)
{ return make_binexpr<std::minus<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator *(L&& l, R&& r)
{ return make_binexpr<std::multiplies<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator /(L&& l, R&& r)
{ return make_binexpr<std::divides<>>(cured(std::forward<L>(l)), cured(std::forward<R>(r))); }
template <class L, class R> auto operator %(L&& l, R&& r)
{ return make_binexpr<std::modulus<>>(cured(std::forward<L>(l)), std::forward<R>(r)); }
template <typename T> auto val(T const& v)
{ return cured(v); }
namespace impl {
template <class T>
static constexpr auto is_indexable(T const&) -> decltype(std::declval<T const&>()[0], std::true_type{}) { return {}; }
static constexpr auto is_indexable(...) -> decltype(std::false_type{}) { return {}; }
struct {
template <class T> size_t operator()(T const& v) const { return (*this)(v, is_indexable(v)); }
template <class T> size_t operator()(T const& v, std::true_type) const { return v.size(); }
template <class T> size_t operator()(T const&, std::false_type) const { return 0; }
template <class T> size_t operator()(Literal<T> const& l) const { return (*this)(l.value); }
template <class L, class R, class Op>
size_t operator()(BinaryExpr<L,R,Op> const& be) const { return (*this)(be.get_lhs()); }
} size;
struct {
template <class T>
auto operator()(size_t i, T const& v) const { return (*this)(i, v, is_indexable(v)); }
template <class T>
auto operator()(size_t i, T const& v, std::true_type) const { return v[i]; }
template <class T>
auto operator()(size_t, T const& v, std::false_type) const { return v; }
template <class T> auto operator()(size_t i, Literal<T> const& l) const { return (*this)(i, l.value); }
template <class L, class R, class Op>
auto operator()(size_t i, BinaryExpr<L,R,Op> const& be) const {
return be.get_op()((*this)(i, be.get_lhs()), (*this)(i, be.get_rhs()));
}
} eval_at;
}
template <typename T> size_t size(T const& v) { return impl::size(v); }
template <typename T> auto eval_at(size_t i, T const& v) { return impl::eval_at(i, v); }
}
#include <vector>
template <class value_t>
struct Vector : std::vector<value_t> {
using data_t = std::vector<value_t>;
typedef value_t value_type;
using data_t::data_t;
template <typename Expr>
Vector(Expr const& expr) { *this = expr; }
template <typename Expr>
Vector& operator=(Expr const& expr) {
this->resize(size(expr));
for (size_t i = 0; i < this->size(); ++i)
this->at(i) = eval_at(i, expr);
return *this;
}
friend std::ostream &operator<<(std::ostream &os, const Vector &v) {
for (auto& el : v) os << " " << el;
return os;
}
};
int main() {
Vector<double> a { 1, 2, 3 };
using ETL::operator+;
using ETL::operator*;
//std::cout << typeid(a + a * 4 / 2).name() << "\n";
#define DD(x) std::cout << typeid(x).name() << " size: " << ETL::size(x) << " result:" << (x) << "\n"
DD(a * -100.0);
auto b = a + a + a;
auto c = a;
std::cout << size(b) << "\n";
std::cout << (a + a + a + a) << "\n";
std::cout << a * 4.0 << "\n";
std::cout << b + c << "\n";
std::cout << (a + a + a + a) - 4 * a << "\n";
}
Prints
ETL::BinaryExpr<ETL::Literal<Vector<double>&>, ETL::Literal<double>, std::multiplies<void> > size: 3 result: -100 -200 -300
3
4 8 12
4 8 12
4 8 12
0 0 0

Deducing const from operator T &()

Issue is that different compiler's produces different output (clang/gcc) and so that makes me think that this usage is undefined behavour. However my goal is to deduce const when assigning reference.
Output with:
clang-3.6 -> not const
gcc-4.8.4 -> const
#include <iostream>
#include <type_traits>
struct AnyReference {
template <typename RT> AnyReference(RT &a_var) : _ptr(&a_var) {}
template <typename T> operator T &() const
{
if (std::is_const<T>::value) {
std::cout << "const\n";
}
else {
std::cout << "not const\n";
}
return *reinterpret_cast<T *>(_ptr);
}
void *_ptr;
};
int main()
{
int i(5);
AnyReference a(i);
const int &c = a;
}
One possibility based on idea of Ben Voight
struct AnyReference {
template <typename RT> AnyReference(RT &a_var) : _ptr(&a_var) {}
template <typename T> operator T &() const { return operatorTand<T>(); }
template <typename T> operator const T &() const
{
return operatorTand<const T>();
}
private:
template <typename T> T &operatorTand() const
{
if (std::is_const<T>::value) {
std::cout << "const\n";
}
else {
std::cout << "not const\n";
}
return *reinterpret_cast<T *>(_ptr);
}
void *_ptr;
};

Unclear C++ syntax in operator overloading

I'm still new to c++ and trying to understand the Expression Templates. I came across an example code on Wikipedia. I Understood most of the program and how it works but I'm not clear how these lines are interpreted by compiler:
operator A&() { return static_cast< A&>(*this); }
operator A const&() const { return static_cast<const A&>(*this); }
from the base expression template class below.
Usually the syntax of operator overloading is return_datatype operator+ (args){body} (e.g for + operator) but this gives errors and the ones in the function compiles without any error. Can anybody explain these two lines? What does A& and A const& before the operators do? And why A& operator() (){} and A const& operator() (){} doesn't work? It gives error:
no matching function for call to 'Vec::Vec(const Expr<Vec>&)'
ExprSum(const Expr<A>& a, const Expr<B>& b): _u(a), _v(b) {}
-Pranav
The complete code:
#include <iostream>
#include <vector>
#include <cassert>
using namespace std;
template <class A>
class Expr{
public:
typedef std::vector<double> container_type;
typedef typename container_type::size_type size_type;
typedef typename container_type::value_type value_type;
typedef typename container_type::reference reference;
size_type size() const {return static_cast<A const&>(*this).size(); }
value_type operator [] (size_t i) const {return static_cast<A const&> (*this)[i];}
operator A&() { return static_cast< A&>(*this); }
operator A const&() const { return static_cast<const A&>(*this); }
};
class Vec : public Expr<Vec> {
private:
container_type x;
public:
Vec(){}
Vec(size_type length) :x(length) {}
size_type size() const { return x.size(); }
reference operator [] (size_type i){
assert(i < x.size());
return x[i];
}
value_type operator [] (size_type i) const {
assert(i < x.size());
return x[i];
}
template <class A>
void operator = (const Expr<A>& ea){
x.resize(ea.size());
for(size_t i = 0; i < x.size(); i++){
x[i] = ea[i];
}
}
};
template <class A, class B>
class ExprSum : public Expr <ExprSum <A,B> >{
private:
A _u;
B _v;
public:
typedef Vec::size_type size_type;
typedef Vec::value_type value_type;
ExprSum(const Expr<A>& a, const Expr<B>& b): _u(a), _v(b) {}
value_type operator [] (size_t i) const { return (_u[i] + _v[i]); }
size_type size() const { return _u.size(); }
};
template <class A, class B>
ExprSum <A,B> const operator + (Expr<A> const& u, Expr<B> const& v){
return ExprSum <A,B> (u,v);
}
int main(){
size_t n = 10;
Vec x(n);
Vec y(n);
Vec z;
for(size_t i = 0; i < n; i++){
x[i] = i;
y[i] = 2*i;
}
z = x + y;
cout << z[7] << endl;
cout << "Hello world!" << endl;
return 0;
}
This is a conversion operator. It looks similar to a normal overloaded operator, but it doesn't have a specified return type, and in place of the operator symbol you have the conversion target type.

Strange behavior of templated operator<<

I cant understand a behavior of operator<< in my class:
header:
#ifndef VECTOR_H_
#define VECTOR_H_
#include <string>
#include <iostream>
template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;
T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);
friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);
std::string toString();
~Vector();
};
#endif /* VECTOR_H_ */
vector.cpp
#include "Vector.h"
#include <string>
#include <sstream>
template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}
template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}
template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}
template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}
template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}
template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}
template<class T>
int Vector<T>::size() const {
return next;
}
template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract
length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}
template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}
template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}
template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}
template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}
template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}
template<class T>
Vector<T>::~Vector() {}
and i run this code with main.cpp
#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}
the magic is in operator<< declaration in header. if i delete CONST modifier, compiler says: Undefined reference to operator<<, but with const it works. It is interesting that in my implementation, in cpp, I doesn't have CONST.
btw, how to solve warnings with warning: friend declaration declares a non-template function for operators?
You should learn how to boil this down to a Short, Self-Contained, Compilable Example aka Minimal Working Example.
Here's an SSCCE that demonstrates the problem:
#include <iostream>
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
T get() const { return m; }
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}
// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}
int main()
{
Vector<int> v(42);
std::cout << v;
}
Note that it's only about 30 lines long and fits onto one screen w/o scroll bars.
Now, the problem is based upon the friend declaration inside your class template:
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
This looks up a function named operator<< in the surrounding scopes, to befriend this already existing function. But it doesn't find any that matches those parameter type. Therefore, it declares a new function in the surrounding (= global) namespace. This function looks like this:
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
(in the global namespace)
Note: it can only be found via Argument-Dependent Lookup if it's only declared via a friend-declaration.
Now, you later declare a function template of the same name. But the compiler cannot know that you meant to befriend this function template when you wrote the friend declaration inside you class template before. So those two, the friend function and the function template, are unrelated.
What happens now is the usual overload resolution. The function template is preferred if you don't add a const, since you call it with a non-const argument:
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const
for this argument of type Vector<int>, the binding to Vector<int>& of the function template (specialization) is preferred over the binding to the Vector<int> const& of the friend function. Hence, the function template is chosen, which has a definition (function body) and everything compiles, links and works. Note that the function template is not befriended, but this doesn't raise an error since you don't use any private members.
Once you add the const to the function template, the function template is no longer a better match for the argument. As we have a function and a function template with the same overload "rank", the non-template is preferred. Ergo, the friend function is called, which has no definition => a linker error occurs.
The simplest solution is to define the friend function inside the class definition:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};
A solution using forward-declarations:
template<class T>
class Vector;
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
Now, the compiler can find the forward-declared function template and befriend this existing function (the specialization of the function template) instead of declaring a new function.
A solution befriending the whole function template:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
In this solution, the friend-declaration declares a function template, and the later declaration at namespace scope following the class' definition redeclares this function template.