1

I'm currently learning C++ and I created a little array-class.

Problem: I can't initialize the array in the object with the constructor.

What do I need to write, to initialize this member? (I'm sure that something with the syntax is wrong.)

Code:

ary.h:

template<typename T_datatype>
class ary {

private:
    T_datatype* T_dataptr;

public:
    ary<T_datatype>(T_datatype* T_ptr) : T_dataptr(T_ptr) {}
};

main.cpp:

#include "ary.h"

int main()
{
    ary<int> array_int = {2, 3, 4}; //is it something like that?...

    return 0;
}
5
  • 1
    Could you please add error message? Commented Aug 20, 2020 at 21:56
  • it says "syntax error, expected ;" Commented Aug 20, 2020 at 21:59
  • For which line? Please be as specific as possible. When in doubt just copy and paste the entire message. Commented Aug 20, 2020 at 22:00
  • Hint: Every line in a declaration requires ;. When the compiler alerts you to problems like this check which line the error references and ensure it's properly terminated. Commented Aug 20, 2020 at 22:01
  • ok, but it's german: error C2143: Syntaxfehler: Es fehlt ";" vor "<" Commented Aug 20, 2020 at 22:03

3 Answers 3

3

The constructor you have implemented expects an int* pointer as input, but {2, 3, 4} does not decay to an int*, so no, the syntax you have shown will not work given the class you have implemented so far.

If you know the exact array size at compile-time, you could do this using std::array instead:

#include <array>

template<typename T, size_t N>
struct ary {
    std::array<T, N> data;
    ...
};
#include "ary.h"

int main()
{
    ary<int, 3> array_int1{2, 3, 4};

    ary<int, 3> array_int2 = {2, 3, 4};

    ary<int, 3> array_int3 = {{2, 3, 4}};

    return 0;
}

Otherwise, if you really want ary to have a pointer to some array data, you could declare an actual array first, and then pass it in to the constructor, eg:

template<typename T>
class ary {
private:
    T *dataptr;
    ...

public:
    ary(T* ptr) : dataptr(ptr) {}
    ...
};
#include "ary.h"

int main()
{
    int data[] = {2, 3, 4};
    ary<int> array_int(data);
    ...

    return 0;
};

But consider giving your class a constructor that takes a std::initializer_list as input instead, and then have the class allocate its own array internally (just be sure to follow the Rule of 3/5/0), eg:

#include <algorithm>
#include <utility>

template<typename T>
class ary {
private:
    T *dataptr = nullptr;
    int datasize = 0;

public:
    ary() = default;

    ary(const ary &src)
        : ary()
    {
        if (src.dataptr && src.datasize > 0)
        {
            dataptr = new T[size];
            datasize = src.datasize;
            std::copy(src.dataptr, src.dataptr+src.datasize, dataptr);
        }
    }

    ary(ary &&src)
        : dataptr(src.dataptr), datasize(src.datasize)
    {
        src.dataptr = nullptr;
        src.datasize = 0;
    }

    ary(T* ptr, int size)
        : dataptr(new T[size]), datasize(size)
    {
        std::copy(ptr, ptr+size, dataptr);
    }

    ary(std::initializer_list<T> l)
        : dataptr(new T[l.size()]), datasize(l.size())
    {
        std::copy(l.begin(), l.end(), dataptr);
    }

    ~ary()
    {
        delete[] dataptr;
    }

    ary& operator=(ary rhs)
    {
        std::swap(dataptr, rhs.dataptr);
        std::swap(datasize, rhs.datasize);
        return *this;
    }

    ...
};
#include "ary.h"

int main()
{
    ary<int> array_int1;

    ary<int> array_int2 = {2, 3, 4};

    int data[] = {2, 3, 4};
    ary<int> array_int3{data, 3};

    ary<int> array_int4{array_int2};

    ary<int> array_int5{std::move(array_int3)};

    ...

    return 0;
}

A better option is to use std::vector instead, and let it do all the work for you, eg:

#include <vector>

template<typename T>
class ary {
private:
    std::vector<T> data;

public:
    ary() = default;

    // the copy/move constructors, copy/move assignment operators,
    // and destructor will be implicitly generated for you...

    ary(T* ptr, int size) : data(ptr, size) {}
    ary(std::initializer_list<T> l) : data(l) {}

    ...
};
#include "ary.h"

int main()
{
    ary<int> array_int1;

    ary<int> array_int2 = {2, 3, 4};

    int data[] = {2, 3, 4};
    ary<int> array_int3{data, 3};

    ary<int> array_int4{array_int2};

    ary<int> array_int5{std::move(array_int3)};

    ...

    return 0;
}
Sign up to request clarification or add additional context in comments.

2 Comments

In the real world you would use std::array or std::vector directly. No need to build wrappers around it. Also why not suggest the most obvious solution? struct Array { T data[SIZE]; }
"No need to build wrappers around it" - that depends on the extra functionality you want to add to it. Encapsulation makes sense. "Also why not suggest the most obvious solution? struct Array {T data[SIZE]; }" - added.
1

The constructor:

ary<T_datatype> ... 

should be named simply:

ary ... 

i.e. without the template parameter.

The line in main:

ary<int> array_int = {2, 3, 4};

is expecting either a constructor that gets three ints or a constructor that gets std::initializer_list<int> neither of them exist in your class.

5 Comments

This still won't compile. You can't pass a brace-init list to the constructor expecting a pointer.
Well, ok, guess we wait for the OP to post a new question for that error then :)
The <T_datatype> in the constructor is unnecessary but harmless.
@cigien I'll accept your knowledge of such things! However, both MSVC and clang-cl (set to use the "preview" C++20 Standard) accept it.
@AdrianMole Hmm, I'm fairly certain I heard this somewhere. gcc recently started giving an error, so I asked a question to make sure.
0

Unfortunately, C++ does not allow compound literals - a feature of the C language that could be useful here. Instead, you will need to declare your array 'argument' to the constructor as a variable in its own right, then pass that to the constructor:

int main()
{
//  ary<int> array_int = { 2, 3, 4 }; //is it something like that?...
    int data[] = { 2, 3, 4 };
    ary<int> array_int{ data }; // "data" will here decay into a pointer to its first element

    return 0;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.