Wrapping the desired Layer into a custom module solves the issue here. Using _norm() from above, you can implement a module with, for example, a Linear Layer + Weight Norm this way:
struct Linear_WN_Impl : torch::nn::Module
{
	torch::Tensor v;
	torch::Tensor g;
	torch::Tensor bias;
	torch::nn::LinearOptions _options;	//Hold Addition Information like (Stride, Padding, ...)

	Linear_WN_Impl(torch::nn::LinearOptions options) : _options(options)
	{
		torch::manual_seed(187); //Only for repeatability and comparison
		//Initialize v, g and bias
		auto default_layer = torch::nn::Linear(_options);
		v = default_layer->weight.data();
		g = _norm(v);
		bias = default_layer->bias.data();
		//Register as Parameters, make trainable
		v = this->register_parameter("v", v);
		g = this->register_parameter("g", g);
		bias = this->register_parameter("bias", bias);
	}
	torch::Tensor forward(torch::Tensor & input)
	{
		//Forward Pass, use v and g to form normalized weight
		return torch::linear(input, v * (g / _norm(v)), bias);
	}
};
TORCH_MODULE(Linear_WN_);

then, you can utilze the module like here for example:
struct Net : torch::nn::Module
{
	Linear_WN_ fc1{ nullptr };
	torch::nn::Linear fc2{ nullptr };

	Net()
	{
                fc1 = register_module("fc1", Linear_WN_(torch::nn::LinearOptions(2, 4)));
		fc2 = register_module("fc2", torch::nn::Linear(4, 1));
	}

	torch::Tensor forward(torch::Tensor x) 
	{
		auto y = torch::sigmoid(fc1->forward(x));
		y = torch::sigmoid(fc2->forward(y));
		return y;
	}
};

I tested and compared it to equivalent Pytorch Code with the built-in weight_norm on the first layer, here are the results of both programs:

grafik1122×459 70.7 KB

and after Training Loop:

grafik1151×733 141 KB

So as you can see, the resulting weights are the same.