【问题标题】:How do I properly implement "operator()" with "if constexpr" so that it works with std::generate?如何使用“if constexpr”正确实现“operator()”,以便它与 std::generate 一起使用?
【发布时间】:2021-05-29 16:40:28
【问题描述】:

我正在尝试编写一个类,该类将使用容器具有的类型填充随机数的容器:

template<typename random_type>
class rand_helper {
private:
    std::mt19937 random_engine;
    std::uniform_int_distribution<int> int_dist;
    std::uniform_real_distribution<double> real_dist;

public:
    rand_helper() = delete;
    rand_helper(random_type left_b, random_type right_b);
    random_type operator()();

};

template<typename random_type>
rand_helper<random_type>::rand_helper(const random_type left_b, const random_type right_b) :random_engine{ std::random_device{}()} {
    if constexpr (std::is_same_v<random_type, double>)
        real_dist(left_b, right_b );
    else
        int_dist( left_b, right_b );
}

template<typename random_type>
random_type rand_helper<random_type>::operator()() {
    if constexpr (std::is_same_v<random_type, double>)
        return real_dist(random_engine);
    else
        return int_dist(random_engine);
}

但是这里某处发生了错误,因为当我调用 std::generate 时,我得到了很多错误:

template<typename T,typename vec_type = typename T::value_type>
void fill_contain(T& container,vec_type left_b=vec_type(0), vec_type right_b= vec_type(100)) {
    std::generate(std::begin(container),std::end(container), rand_helper<vec_type>(left_b ,right_b));   
}

我认为这可能是因为 if constexpr 但如果只是离开:

template<typename random_type>
random_type rand_helper<random_type>::operator()() {
    return int_dist(random_engine);
}

那么仍然返回相同的错误。 这是我得到的错误列表:

Error   C2825   '_Urng': must be a class or namespace when followed by '::'
Error   C2510   '_Urng' : left of '::' must be a class / struct / union
Error   C2061   syntax error : identifier 'result_type'
Error   C2065   '_Ty1' : undeclared identifier
Error   C2923   'std::conditional_t' : '_Ty1' is not a valid template type argument for parameter '_Ty2'

函数调用如下:

 std::vector<int> for_sort;
    fill_contain(for_sort);

【问题讨论】:

  • 重新打开:这个问题显然不是在问如何在编译时生成随机数,那里的答案都没有解释这个编译器错误。
  • @chris 哦,你是对的,我误读了这个问题。那是一个粗心的关闭,谢谢你抓住它。

标签: c++ random template-instantiation


【解决方案1】:

无论if constexpr 是什么,您的代码都无法编译。仅使用模板类可能不会出现编译错误的原因是,它是一个模板,因此没有任何实际实例被编译。如果添加:

template class rand_helper<int>;

强制实例化intrandom_type,你会得到大量的编译错误输出。

具体来说,你会被告知你需要一个伪随机生成器来构造一个uniform_int_distribution&lt;int&gt;


不管上述情况 - 你可以使用类似的东西:

template <typename T>
using uniform_distribution = std::conditional_t<
    std::is_integral_v<T>,
    std::uniform_int_distribution<T>, 
    std::uniform_real_distribution<T>
>;

只有一个分发成员。在这种情况下,你甚至可能不需要你的助手类。

【讨论】:

  • 即可以将std::条件与std::uniform_int_distributionstd::uniform_real_distribution一起使用?据我记得,它从几个中输出一个通用类型,这里也可以从这样的元素中完成?
  • @Alpharius:是的。
  • 我什至无法想象它应该如何工作。我认为可以通过模板选择一种类型。看看你所说的例子会很有趣跨度>
  • 非常感谢,我什至没有考虑。也就是说,在您看来,最好使用您的uniform_distribution 并在 lambda 函数的某处定义一个随机生成器(对于例如)而不是制作函子?
  • @Alpharius:我会从 lambda 开始。
【解决方案2】:

为了避免使用非浮点类型实例化 std::uniform_real_distribution 模板类并获得可能令人困惑的诊断,我更喜欢使用这样的模板特化而不是 std::conditional_t

namespace detail
{
    template <typename T, typename AlwaysVoid = void>
    struct uniform_distribution_impl
    {
        static_assert(sizeof(T) == 0, "T must be integral or floating point");
    };

    template <typename T>
    struct uniform_distribution_impl<
        T, std::enable_if_t<std::is_integral_v<T>>>
    {
        using type = std::uniform_int_distribution<T>;
    };

    template <typename T>
    struct uniform_distribution_impl<
        T, std::enable_if_t<std::is_floating_point_v<T>>>
    {
        using type = std::uniform_real_distribution<T>;
    };
}

template <typename T>
using uniform_distribution = typename detail::uniform_distribution_impl<T>::type;

【讨论】:

  • 很好的补充!
猜你喜欢
  • 2022-01-04
  • 2020-12-13
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
相关资源
最近更新 更多