0

This question is a follow-up question to Why is alloca returning the same address twice?. I've found a way to get a different memory address to both instances by using an array.

vml.h

#pragma once
#include <iostream>


namespace vml {
    // Vectors
    template <typename in_type, const int in_length>
    class vec {
    public:
        vec(in_type* in_data) {
            std::cout << data << std::endl;
            std::copy(in_data, in_data + in_length, data);
        }
        vec() {
            data = nullptr;
        }
        in_type& operator()(int index) const {
            _ASSERT(0 <= index && index < in_length);
            return data[index];

        }

    private:
        in_type data[in_length];
    };

main.cpp

#include <memory>
#include "vml.h"

int main() {
    int list[] = { 1,2,3 };
    int list2[] = {2,4,6 };

    vml::vec<int, 3> a(list);
    vml::vec<int, 3> b(list);

    a(1) = 3;
    
    return 0;
}

However, when I run the code I get an error

Error C2440 'return': cannot convert from 'const in_type' to 'in_type &'

Since the return value is 'data[index]' this must mean that it is constant, however, I did not define it as a constant so why is this happening?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335

3 Answers3

2

You miss the const in return type of your operator()()

in_type const & operator()(int index) const {
        _ASSERT(0 <= index && index < in_length);
        return data[index];
    }

When you declare member function with const modifier all class members inside became constant while using inside it

If you want non-const reference as result you shouldn't use const modifier on that member function:

in_type & operator()(int index) {
    _ASSERT( 0 <= index && index < in_length);
    return data[index];
}
user2807083
  • 2,962
  • 4
  • 29
  • 37
  • I don't want it to be const as I want to change `data[index]` when I call `a(1) = 3;` for example. I defined data[index] `in_type data[index]` without a const prefix so why is it const? – Joshua Pasa Feb 24 '21 at 14:58
  • then you should not make your function const: `in_type & operator()(int index) { return data[index]; }` – user2807083 Feb 24 '21 at 14:58
  • Thank you it works now!!! I thought the const at the end made it such that the function itself can't change anything so I thought since its returning a value it should be marked as const – Joshua Pasa Feb 24 '21 at 15:02
  • @JoshuaPasa The `const` at the end of the function means the function is safe to call on a `const` instance of the object. – François Andrieux Feb 24 '21 at 15:24
1

For starters this constructor

vec() {
    data = nullptr;
}

is invalid. Arrays are non-modifiable lvalues.

This member function

    in_type& operator()(int index) const {
        _ASSERT(0 <= index && index < in_length);
        return data[index];

    }

is a constant member function. So the array data is considered as a constant array.

You could overload the function like

    const in_type& operator()(int index) const {
        _ASSERT(0 <= index && index < in_length);
        return data[index];
    } 

and

    in_type& operator()(int index) {
        _ASSERT(0 <= index && index < in_length);
        return data[index];
    }

In this case in this statement

a(1) = 3;

there will be called the non-constant member function.

Pay attention to that this constructor

    vec(in_type* in_data) {
        std::cout << data << std::endl;
        std::copy(in_data, in_data + in_length, data);
    }

is unsafe. And at least the parameter should have the qualifier const.

The constructor could be declared like

    vec( const in_type *in_data, size_t n );
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

for fixing it, you must overload the operator() twice

in_type const &operator()(int index) const {
    _ASSERT(0 <= index && index < in_length);
    return data[index];
}
in_type &operator()(int index) {
    _ASSERT(0 <= index && index < in_lenght);
    return data[index];
}

You have to do it like that because when you create a const object any member of the object are const so methods can not return a reference but it must return a const reference, you can use this method even with non const methods but you can not change the values of members, that's why you need in_type operator()(int index). The important thing is that when you qualify a method as const it means that is available also for const objects, so it must handle any member as if it is const.

Linus
  • 50
  • 3