首页 > 解决方案 > 带有 std::variant 和 std::visit 的联合模板

问题描述

我正在使用一个模板库,因为在我的代码中,一个模板参数可以假设一个有限范围的值,我决定在建议下使用 std::variant 并在其中声明我可能需要的所有对象:

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

我从未使用过此实用程序。

要访问我必须使用的 TemplateClass 的方法std::visit,但有时它可以工作,而其他的则不能,比如no member function XXX in std::variant < .... >“在函数模板专业化的实例化中......” [我什至不明白这里有什么问题]

具体来说,我正在使用Eigen::Tensor库,当我调用类似rank(),的方法时dimension(n),它可以工作,而对于类似的方法dimensions()setRandom()它不会。

下面是我的实施草稿

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<...>'
}

我是否std::visit以错误的方式使用?

- - 编辑 - -

在@florestan 的建议下,我解决了与 相关的问题dimensions(),同时setRandom得到以下信息:

在 /..../ main.cpp 包含的文件中 在此处输入图像描述 ,此处需要 在此处输入图像描述

标签: c++templatesc++17unioneigen

解决方案


您需要为所有可能的替代方案返回相同的类型。例如,在 的情况下dimension,您需要将数组元素复制到向量中。

这样的事情应该会有所帮助:

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

第二个错误是因为你没有调用std::visit正确的方法。它需要两个参数,第一个是要访问的函数,第二个是要访问的变量。以下应该工作。

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

实时代码: https ://godbolt.org/z/vq4PYo


推荐阅读