How to define a default constructor on a custom module

I’m starting to use the C++ frontend and want to create a custom Module but I am not sure how to define the default constructor so my Model can use it.

Take a simple example of the Convolution below that just wraps Conv1d, SiLU and sets the padding…

struct Convolution : Module {

    Convolution(int size, int outsize, int k, int stride)  {
        conv = register_module("conv", Conv1d(Conv1dOptions(size, outsize, k).stride(stride).padding(k/2)));
        activation = register_module("activation", SiLU());
    }

    torch::Tensor forward(torch::Tensor x) {
        return activation(conv(x));
    }
    Conv1d conv{nullptr};
    SiLU activation{nullptr};

};

struct Model : Module {
    Model(int size, int outsize) {
        conv1 = Convolution(1, 4, 5, 1);
        conv2 = Convolution(4, 16, 5, 1);
        conv3 = Convolution(16, outsize, 19, 5);
    }
    Convolution conv1{nullptr}, conv2{nullptr}, conv3{nullptr};
};

This leads to the following error from the compiler…

error: no matching constructor for initialization of 'Convolution'
    Convolution conv1{nullptr}, conv2{nullptr}, conv3{nullptr};
                     ^~~~~~~~~
note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'nullptr_t' to 'const Convolution' for 1st argument
struct Convolution : Module {
       ^

I’m not sure but wouldn’t the c’tor in Model need to use register_module for each Convolution object as well?

Yes but register_module takes a ModuleHolder not a Module so I think the following is correct (and this also solves the original question I had).

struct ConvolutionImpl : Module {

    ConvolutionImpl(int size = 1, int outsize = 1, int k = 1, int stride = 1)  {
        conv = register_module("conv", Conv1d(Conv1dOptions(size, outsize, k).stride(stride).padding(k/2)));
        activation = register_module("activation", SiLU());
    }

    torch::Tensor forward(torch::Tensor x) {
        return activation(conv(x));
    }

    Conv1d conv{nullptr};
    SiLU activation{nullptr};

};

typedef ModuleHolder<ConvolutionImpl> Convolution;

struct Model : Module {
    Model(int size, int outsize) {
        conv1 = register_module("conv1", Convolution(1, 4, 5, 1));
        conv2 = register_module("conv2", Convolution(1, 16, 5, 1));
        conv3 = register_module("conv3", Convolution(16, outsize, 19, 5));
    }
    Convolution conv1{nullptr}, conv2{nullptr}, conv3{nullptr};
};