Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union Template with std::variant and std::visit

I'm using a template library and since in my code one of the template parameters can assume a finite range of values, I decided to use, under suggestion, std::variant and declare in it all the objects I will possibly need:

std::variant<TemplateClass<1>, TemplateClass<2>, ..., TemplateClass<5>>

I never used this utility.

To access the methods of TemplateClass I have to use std::visit, but sometimes it works and other it doesn't, say no member function XXX in std::variant < .... > or "In instantiation of function template specialization ... " [I don't even understand what is the problem here]

Specifically, I'm using Eigen::Tensor library and when I call methods like rank(), dimension(n), it works, while for methods like dimensions() and setRandom() it doesn't.

Below a draft of my implementation

std::variant<Eigen::Tensor<double, 1>, Eigen::Tensor<double, 2>, /* ... */> makeTensor(
    int i, const std::initializer_list<int> dims) {
  switch (i) {
    case 1: {
      Eigen::Tensor<double, 1> T1;
      T1.resize(dims);
      return T1;
    }

    case 2: {
      Eigen::Tensor<double, 2> T2;
      T2.resize(dims);
      return T2;
    }

      /* ... */
  }
}

int main() {
  auto myTensor{makeTensor(2, {4, 5})};  // Tensor 2D 4x5

  // Working methods
  auto rnk = std::visit([](const auto &tensor) { return tensor.rank(); }, myTensor);

  auto dim1 = std::visit([](const auto &tensor) { return tensor.dimension(0); }, myTensor);

  // Not working methods

  auto dimsTens =
      std::visit([](const auto &tensor) { return tensor.dimensions(); }, myTensor);  // 5 times same error saying
  //'In instantiation of function template specialization 'std::visit<(lambda at
  /// home/virginie/Desktop/Project/main.cpp:62:33),
  // std::variant<Eigen::Tensor<double, 1, 0, long>, Eigen::Tensor<double, 2, 0, long>, Eigen::Tensor<double, 3, 0,
  // long>, Eigen::Tensor<double, 4, 0, long>, Eigen::Tensor<double, 5, 0, long>> &>''

  std::visit([&myTensor]() { myTensor.setRandom(); });  // 'No member setRandom() in std::variant<...>'
}

Am I using std::visit in the wrong way?

---- EDIT ----

After the suggestion of @florestan, I have solved the problem related to dimensions(), while with setRandom I get the following:

In file included from /..../ main.cpp enter image description here required from here enter image description here

like image 860
Virginie Avatar asked Aug 31 '26 00:08

Virginie


1 Answers

You need to return the same type for all possible alternatives. In case of dimension, you need to copy the array elements to a vector, for example.

Something like this should help:

 auto dimsTens=std::visit(
    [](const auto &tensor) {
       auto dims = tensor.dimensions();
       return std::vector<int>(dims.begin(), dims.end());
    }, myTensor);

The second error is because you don't call std::visit the right way. It needs two params, first the function and second the variant to visit. The following should work.

std::visit([](auto& t){ t.setRandom();}, myTensor); 

Live code: https://godbolt.org/z/vq4PYo

like image 60
florestan Avatar answered Sep 02 '26 13:09

florestan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!