代码之家  ›  专栏  ›  技术社区  ›  Xirema

为什么我使用std::uniform_random_bit_generator失败了?

  •  3
  • Xirema  · 技术社区  · 9 月前

    给定以下示例程序,它使用 std::uniform_random_bit_generator 概念:

    #include<random>
    #include<print>
    
    template<std::uniform_random_bit_generator PRNG>
    void test(PRNG && rng) {
        std::uniform_int_distribution<int> dist{1, 7};
        std::print("{}\n", dist(rng));
    }
    
    int main() {
        std::minstd_rand engine{std::random_device{}()};
        test(engine);
    }
    

    我希望这段代码能够编译,但是 it fails 并显示以下错误消息。

    让我困惑的是,我还没有定义任何新类型:这使用了一个内置的C++随机位生成器,在使用其他生成器(mt19937等)时,我也会遇到同样的错误。为什么会这样?我是否错误地应用了这个概念?

    叮当声:

    <source>:12:5: error: no matching function for call to 'test'
       12 |     test(engine);
          |     ^~~~
    <source>:5:6: note: candidate template ignored: constraints not satisfied [with PRNG = std::minstd_rand &]
        5 | void test(PRNG && rng) {
          |      ^
    <source>:4:10: note: because 'std::linear_congruential_engine<unsigned long, 48271, 0, 2147483647> &' does not satisfy 'uniform_random_bit_generator'
        4 | template<std::uniform_random_bit_generator PRNG>
          |          ^
    /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/bits/uniform_int_dist.h:57:4: note: because '_Gen::min()' would be invalid: type 'std::linear_congruential_engine<unsigned long, 48271, 0, 2147483647> &' cannot be used prior to '::' because it has no members
       57 |         { _Gen::min() } -> same_as<invoke_result_t<_Gen&>>;
          |           ^
    1 error generated.
    Compiler returned: 1
    

    通用条款14.2:

    <source>: In function 'int main()':
    <source>:12:9: error: no matching function for call to 'test(std::minstd_rand&)'
       12 |     test(engine);
          |     ~~~~^~~~~~~~
    <source>:5:6: note: candidate: 'template<class PRNG>  requires  uniform_random_bit_generator<PRNG> void test(PRNG&&)'
        5 | void test(PRNG && rng) {
          |      ^~~~
    <source>:5:6: note:   template argument deduction/substitution failed:
    <source>:5:6: note: constraints not satisfied
    In file included from /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/random.h:35,
                     from /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/random:48,
                     from <source>:1:
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h: In substitution of 'template<class PRNG>  requires  uniform_random_bit_generator<PRNG> void test(PRNG&&) [with PRNG = std::linear_congruential_engine<long unsigned int, 48271, 0, 2147483647>&]':
    <source>:12:9:   required from here
       12 |     test(engine);
          |     ~~~~^~~~~~~~
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h:53:13:   required for the satisfaction of 'uniform_random_bit_generator<PRNG>' [with PRNG = std::linear_congruential_engine<long unsigned int, 48271, 0, 2147483647>&]
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h:55:10:   in requirements  [with _Gen = std::linear_congruential_engine<long unsigned int, 48271, 0, 2147483647>&]
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h:57:20: note: the required expression '_Gen::min()' is invalid
       57 |         { _Gen::min() } -> same_as<invoke_result_t<_Gen&>>;
          |           ~~~~~~~~~^~
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h:58:20: note: the required expression '_Gen::max()' is invalid
       58 |         { _Gen::max() } -> same_as<invoke_result_t<_Gen&>>;
          |           ~~~~~~~~~^~
    /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/uniform_int_dist.h:59:18: note: nested requirement 'std::bool_constant<((bool)(_Gen::min() < _Gen::max()))>::value' is not satisfied
       59 |         requires bool_constant<(_Gen::min() < _Gen::max())>::value;
          |         ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
    Compiler returned: 1
    
    1 回复  |  直到 9 月前
        1
  •  2
  •   Raed Addala    9 月前

    即使对我来说,这也是一个棘手且有点令人困惑的C++部分 <random> 文档和C++20 Concepts ,原因如下:

    问题所在

    这个 uniform_random_bit_generator 这个概念之所以失败,是因为两个相关的问题:

    • 参考&;类型问题 :当您使用PRNG&&在您的模板中,C++试图检查引用类型(如minsd_rand&)的概念要求,而不是实际类型(minsd_rand)。
    • 静态范围要求 :这个概念需要静态min()和max()函数,因为它们定义了该生成器类型的任何实例都可以产生的可能值的范围。它们是静态的,因为这些边界是生成器类型本身的属性,而不是特定实例的属性(比如minst_rand总是在0和2147483647之间生成)。

    解决方案

    我们必须直接传递PRNG,而不是用转发引用传递它,或者绕过概念检查。

    对于第二种解决方案,我们将使用以下内容: std::remove_reference_t

    所以应该是这样的:

        template<typename PRNG>
        requires std::uniform_random_bit_generator<std::remove_reference_t<PRNG>>
        void test(PRNG && rng)
    

    希望这是一个有帮助的答案。在C++中,概念对我来说仍然是一个具有挑战性的话题。