0

I created a template class vect that allows me to create arrays of elements of type T, access them from 1 to n (instead of 0 to n-1) and permute them (I have to permute them that way instead of permuting them the classical way).

Here's the header file:

#ifndef VECT_HPP

#define VECT_HPP

#include <vector>

template <class T>
class vect
{
public:
    vect(int=0);
    ~vect();
    void show(void) const;
    void permute(int,int);
    T& operator[](int);
    const T& operator[](int) const;
    void init_perm(void);
private:
    int n;
    double* p;
    std::vector<int> s;
};

#endif /* GUARD_VECT_HPP */
#include "vect.cpp"

and here's the source file:

#ifndef VECT_CPP
#define VECT_CPP

#include "vect.hpp"
#include <iostream>

using namespace std;

template <class T>
vect<T>::vect(int a): n(a)
{
    p=new double[n];
    s.resize(n);
    init_perm();
}

template <class T>
vect<T>::~vect()
{
    delete [] p;
}

template <class T>
void vect<T>::show(void) const
{
    for (int i = 0; i < n; i++)
        cout << p[i] << endl;
}

template <class T>
void vect<T>::permute(int a,int b)
{
    static int c;
    a--;
    b--;
    c=s[a];
    s[a]=s[b];
    s[b]=c;
}
template <class T>
T& vect<T>::operator[](int i)
{
    return p[s[i-1]-1];
}

template <class T>
const T& vect<T>::operator[](int i) const
{
    return p[s[i-1]-1];
}

template <class T>
void vect<T>::init_perm(void)
{
    for (int i = 0; i < n; i++)
        s[i]=i+1;
}

#endif

and here's the file main.cpp that I uesd to test the class:

#include "vect.hpp"
#include <iostream>

using namespace std;

int main(void)
{
    vect<int> v(5);
    v.show();
    for (int i = 1; i <=5; i++)
        v[i]=10*i;
    v.show();
    cout << "Permuted 3 and 5" << endl;
    v.permute(3,5);
    v.show();
    v.init_perm();
    cout << "Initialized permutations" << endl;
    v.show();
    return 0;
}

I get the following error:

In file included from vect.hpp:25:0,
                 from main.cpp:1:
vect.cpp: In instantiation of ‘T& vect<T>::operator[](int) [with T = int]’:
main.cpp:11:6:   required from here
vect.cpp:43:19: error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’
  return p[s[i-1]-1];

I searched on Internet about this error and how it can be caused by a bad implementation of operator[], but after correction I still have the same error, even when I return p[i-1] instead of p[s[i-1]].

Could you please help me?

Scientifica
  • 169
  • 1
  • 10
  • Normally array and vector indexes are zero-based. Why have you changed that to make your vector indexes one-based? – Some programmer dude Feb 10 '17 at 06:48
  • 1
    `double* p;` - why? – Mat Feb 10 '17 at 06:48
  • 1
    `double* p;` needs to be `T* p;`. Sounds like a typo. – R Sahu Feb 10 '17 at 06:50
  • `p` is a `double *`. A reference to `p[i]` cannot be converted into a reference to `int`. – Peter Feb 10 '17 at 06:53
  • @Someprogrammerdude I'm a math major studying numerical linear algebra. We're used to represent vectors with one-based indexes instead of zero-based indexes. Indeed it's not a real trouble, but when reading a program, it's inconvenient to us since we always thing about vectors with one-based indexes. – Scientifica Feb 10 '17 at 11:52
  • @Mat Yes you're right should be T*. Thank you! – Scientifica Feb 10 '17 at 11:54
  • @RSahu Yes you're right should be T*. Thank you! – Scientifica Feb 10 '17 at 11:54
  • @Peter Yes you're right should be T*. Thank you! – Scientifica Feb 10 '17 at 11:54
  • On the other hand *all other* programmers reading your code will be confused. Especially since you have a mix of containers where some use zero-based indexing and others using one-based, in the same program. Try to follow conventions, when doing math use one-based indexes, when doing programming use zero-based. It will be simpler in the long run. :) – Some programmer dude Feb 10 '17 at 11:55
  • @Someprogrammerdude Yes you're right, thank you very much for your advices :) One small thing is that I program using zero-based indexes when doing programming as you said; CS courses. In this course we really think mathematically and makes it easier to us (or to me at least) to use one based indexing when dealing with vectors and matrices for scientific computing. It's a matter of communities: in Matlab for example (a popular software providing a programming language for scientific computing), indexing is one-based. But you're right, having two mixed indexing methods is confusing. – Scientifica Feb 10 '17 at 12:43

2 Answers2

2

The problem stems from the type-mismatch of p compared to the template T.

You have an array of double, pointed to by p. And the template T is an int. Normally that's not a big problem since double can implicitly be converted to an int. But this isn't the normal case, because you want to return a reference to int.

The compiler does the conversion to int for you, but this converted value is an rvalue and a temporary, and references can't bind to rvalues.

The solution is to not have a mismatch of the types, and have p point to an array of T instead. Or better yet, have it be a std::vector.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

The problem is here:

template <class T>
T& vect<T>::operator[](int i)
{
    return p[s[i-1]-1];
}

in your example, T is deduced to int, but p is always of type double. So when you return p[s[i-1]-1], an int& tries to bind to a double. At this point that double value implicitly is converted to a rvalue int which cannot be bound to a int&.

frogatto
  • 28,539
  • 11
  • 83
  • 129