Question

In the following simplified code I try something like this:

struct A{};
struct B : public A {};
void func(A &a) {}
B b;
func(b);

Typically this is working but in the following more complicated code it doesn't work. I guess that I missing something on templates.

Why it is impossible to upcast from DenseVector<container_reference<std::array<double, 25ull>>> to container_reference<std::array<double, 25ull> >& ?

#include <iostream>
#include <vector>
#include <array>
#include <cassert>

using namespace std;


template<class C>
struct container_reference
{
    typedef typename C::iterator iterator;
    container_reference(iterator f, iterator e) : f(f), e(e) {}
    void swap(container_reference &c) { std::swap(*f, *(c.f)); /*...and more*/ }
    iterator f,e;
};

template<typename C>
struct DenseVector : public C { using C::C; };

template<typename C>
struct DenseMatrixRect
{
    typedef DenseVector<container_reference<C>> row_vector;
    row_vector row(unsigned int i)
    {
        auto it = container.begin() + i * width;
        return row_vector(it, it + width);
    }
    C container;
    unsigned int width;
};


int main() 
{
    DenseMatrixRect<std::array<double, 25>> m; m.width = 5;
    m.row(0).swap(m.row(1));
    return 0;
}
Was it helpful?

Solution

Your code fails because you try to bind a temporary container_reference returned from row in your call to swap.

You simply forgot to bind a const reference and mark the method itself const:

void swap(const container_reference &c) const { std::swap(*f, *(c.f)); /*...and more*/ }
//        ^^^^^                         ^^^^^

Since you are only swapping the (non-const) content of c and not c itself, you don't need it to be modifyable. Although, it's worth to point out that this is a pretty unusual swap where both arguments are const because they are only placeholders to the real content that is swapped.

OTHER TIPS

Give it a name, then it's an lvalue and the cast works:

auto x = m.row(1);
m.row(0).swap(x);

Another option would be to add a version of swap that takes temporaries:

void swap(container_reference &&c) { std::swap(*f, *(c.f)); /*...and more*/ }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top