1
struct Test {
    int w, h;
    int * p;
};

int main(){
    Test t {
        10,
        20,
        new int[this->h*this->w]
    };
    return 0;
}

I just want to use the w and h in initialization, is there any way to get this?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Biao Cao
  • 141
  • 1
  • 10

2 Answers2

2

First of all - you should avoid calling new (and delete) explicitly, except in rare case; this isn't one of them. Use an std::unique_ptr to hold your allocated memory (see below).

To answer your question: You can't use the members of a struct/class as arguments to a constructor of that struct/class. Conceptually, the arguments are resolved before the constructor runs.

However, you can write a named constructor idiom:

struct Test {
    int w, h;
    std::unique_ptr<int[]> p;

static:
    Test make(int w, int h) {
        return Test{ w, h, std::make_unique<int[]>(w*h) };
    }
};

which would let you write:

auto my_test = Test::make(w, h);

Alternatively, you could just outright implement a constructor which takes only w and h:

struct Test {
    int w, h;
    std::unique_ptr<int[]> p;

    Test(int w_, int h_) : w(w_), h(_), p(std::make_unique<int[]>(w_*h_) { }
};

... but then you would need to write some extra code for a no-parameter constructor and a 3-parameter constructor (if not other methods).

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Do you mean `public:` rather than `static:`? – Galik Jun 04 '20 at 08:21
  • 2
    And I don't see why a normal constructor `Test( int w_, int h_ ) : w( w_ ), h( h_ ), p( std::make_unique< int[] >( w * h ) ) {}` wouldn't do. You could then `Test t { 10, 20 };` with ease...?!? – DevSolar Jun 04 '20 at 08:29
  • @DevSolar: Because I'm assuming OP wants a "plain" struct. But see edit. – einpoklum Jun 04 '20 at 09:13
  • @einpoklum "plain" structs don't really exist in C++. A `struct` is no different than a `class`, except for the default visibility of members is `public` in a `struct` and `private` in a `class`. Otherwise, the compiler treats `struct` and `class` the same in all other regards. – Remy Lebeau Jun 04 '20 at 09:18
  • @RemyLebeau: I know that. I meant in the sense of constructors and destructors being generated by the compiler and the programmer not having to concern themselves with them. – einpoklum Jun 04 '20 at 09:22
0

If you write a constructor for your class, you can take advantage of its member initializer list. In particular, you could exploit the fact that "non-static data member are initialized in order of declaration in the class definition".

Consider this little less trivial example

#include <iostream>
#include <stdexcept>
#include <vector>

class Matrix
{
    int h_{};
    int w_{};
    std::vector<int> d_;
public:
    Matrix() = default;
    Matrix(int h, int w)
        : h_{checked_positive(h)}
        , w_{checked_positive(w)}
        , d_(h_ * w_)             // <-- 
    {}

    void show() {
        std::cout << h_ << ' ' << w_ << ' ' << d_.size() << '\n';
    }
private:
    int checked_positive(int d) {
        if (d < 1)
            throw std::runtime_error{"Dimensions must be positive"};
        return d;
    }
};

int main()
{
    Matrix a(3, 4);

    a.show();
}

Note, though, that some reviewers might find this dependency on the order of declaration of the members an unnecessary one and a maintainability cost.

In alternative, the dependent member could be default-initialized and then modified in the body of the constructor:

class Matrix
{
    std::vector<int> d_;  // <--
    int h_{}, w_{};
public:
    Matrix() = default;
    Matrix(int h, int w)
        : h_{checked_positive(h)}
        , w_{checked_positive(w)}
    {
        d_.resize(h_ * w_);   // <--
    }
// ...  
Bob__
  • 12,361
  • 3
  • 28
  • 42