C++ 返回类型取决于函数参数的数量

C++ return type depending on the number of function arguments

提问人:user2961927 提问时间:9/30/2023 最后编辑:user2961927 更新时间:10/1/2023 访问量:144

问:

我有以下结构:

#define vec std::vector
struct A
{
  std::mt19937 rng;
  std::uniform_real_distribution<double> U;
  A(){}
  A(int sed) 
  {
    rng.seed(sed); 
    U = std::uniform_real_distribution<double>(0, 100000);
  }
  
  
  template <typename T>
  vec<T> get(std::size_t size)
  {
    vec<T> rst(size);
    for (auto &x: rst) x = U(rng);
    return rst;
  }
  
  
  template <typename T>
  vec<vec<T>> get(std::size_t size1, std::size_t size2)
  {
    vec<vec<T>> rst(size1);
    for (auto &x: rst) get(size2).swap(x);
    return rst;
  } 
  
  
  template <typename T>
  vec<vec<vec<T>>> get(std::size_t size1, std::size_t size2, std::size_t size3)
  {
    vec<vec<vec<T>>> rst(size1);
    for (auto &x: rst) get(size2, size3).swap(x);
    return rst;
  }
};

#undef vec

我知道这可能是一个很长的机会,但是如何编写一个成员函数,以便当我这样做时:magicGet()

auto u = magicGet<T>(3, 1, 2, 5);
auto v = magicGet<T>(7, 9, 6, 2, 2);
auto w = magicGet<T>(6);

我将获得 in type , in type 和 in type 等?uvec<vec<vec<vec<T>>>>vvec<vec<vec<vec<vec<T>>>>>wvec<T>

如果不可能,最接近的解决方案是什么?

更新:通过吸收接受的答案和 @Shreeyash Shrestha 的帖子,最简单的解决方案可能是:

  template <typename T, typename... Args>
  auto magicGet(std::size_t size, Args... args)
  {
    if constexpr (sizeof...(args) == 0)
    {
      vec<T> rst(size);
      for (auto &x: rst) x = U(rng);
      return rst;
    }
    else // The code body must be wrapped inside else {} to ensure the compiler
      // knows they are mutually exclusive.
    {
      vec<decltype(magicGet<T>(args...))> rst(size);
      for (auto &x: rst) magicGet<T> (args...).swap(x);
      return rst;
    }
  } 
C++ 模板 variadic-functions 类型特征 variadic

评论

0赞 Shreeyash Shrestha 9/30/2023
您可以尝试对它们使用省略号。而不是为多种类型制作多个模板
2赞 Passer By 9/30/2023
很有可能,您想要的是一个大向量,并自己执行索引计算,而不是嵌套向量。
0赞 user2961927 10/1/2023
@PasserBy 我完全明白你的意思,但我的双手被束缚了。
2赞 Jesper Juhl 10/1/2023
"#define vec std::vector" - using vec = std::vector;恕我直言会更好 - 宏是邪恶的。

答:

1赞 Shreeyash Shrestha 9/30/2023 #1

您可以尝试执行以下操作:

template <typename T, typename... Args>
auto magicGet(int size, Args... args)
{
    vec<T> rst(size);
    if constexpr (sizeof...(args) > 0)
    {
        auto inner = magicGet<T>(args...);
        for (auto &x : rst)  x = inner;
    }
    return rst;
} 

请告诉我它是否有效。 祝你好运!

评论

0赞 LiuYuan 9/30/2023
如果我错了,请纠正我:不应该?if (constexpr ...))if constexpr (...)
0赞 Shreeyash Shrestha 9/30/2023
哎呀。1 分钟我会编辑它。谢谢
0赞 LiuYuan 9/30/2023
先生,我用我的测试代码尝试了您的代码,但没有通过......我不知道我是否误解了,因此我在您的答案下方上传了我的解决方案。你能检查一下吗?
0赞 Shreeyash Shrestha 9/30/2023
我只是试着给出一个基本的想法,即它也可以以这种方式完成。如果它不起作用,我希望这个答案只是一个想法参考,而不是一个实际的答案。虽然它对我来说很正常。我以一种我理解问题的方式重写了整个代码。也许这就是问题所在?
0赞 LiuYuan 9/30/2023
OP 可能希望具有与传入的参数数量相关的多个嵌套级别。例如,如果传入一个参数,则返回类型为 ,而如果传入两个参数,则返回类型为 ,依此类推。在您的回答中,您似乎忘记了为 添加嵌套层。也许你可以考虑使用我在回答中使用的 。vectorvector<int>vector<vector<int>>rstvec<decltype(magicGet<T>(args...))> rst(size)
3赞 LiuYuan 9/30/2023 #2

试试这个:

  template<typename T>
  std::vector<T> magic_func(T value) {
    static_assert(std::is_convertible_v<decltype(value), size_t>);
    std::vector<T> result(static_cast<size_t>(value));

    for (auto& val : result) {
      val = U(rng);
    }

    return result;
  }

  template<typename T, typename... Args>
  auto magic_func(T value, Args... args) {
    static_assert(std::is_convertible_v<decltype(value), size_t>);
    std::vector<decltype(magic_func(args...))> result(static_cast<size_t>(value));
    for (auto& sub_vec : result) {
      magic_func(args...).swap(sub_vec);
    }
    return result;
  }

以下是完整的代码和测试代码:

#include <random>
#include <vector>
#include <iostream>

#define vec std::vector

struct A {
  // Your code ...

  template<typename T>
  std::vector<T> magic_func(T value) {
    static_assert(std::is_convertible_v<decltype(value), size_t>);
    std::vector<T> result(static_cast<size_t>(value));

    for (auto& val : result) {
      val = U(rng);
    }

    return result;
  }

  template<typename T, typename... Args>
  auto magic_func(T value, Args... args) {
    static_assert(std::is_convertible_v<decltype(value), size_t>);
    std::vector<decltype(magic_func(args...))> result(static_cast<size_t>(value));
    for (auto& sub_vec : result) {
      magic_func(args...).swap(sub_vec);
    }
    return result;
  }

};

#undef vec

int main() {
  A a;
  auto result1 = a.magic_func<int>(1);
  static_assert(
      std::is_same_v<decltype(result1),
                     std::vector<int>>
  );
  auto result2 = a.magic_func<int>(1, 2);
  static_assert(
      std::is_same_v<decltype(result2),
                     std::vector<std::vector<int>>>
  );
  auto result3 = a.magic_func<int>(1, 2, 3);
  static_assert(
      std::is_same_v<decltype(result3),
                     std::vector<std::vector<std::vector<int>>>>
  );
}