为何使用std::uniform_random_bit_generator的代码编译失败?
为什么使用
std::uniform_random_bit_generator概念的C++代码编译失败? 我写了一段使用std::uniform_random_bit_generator概念的C++代码,预期能正常编译,但实际编译失败。代码用的是标准库内置的随机位生成器,换成mt19937等其他生成器也会报同样的错误。我是不是错误应用了这个概念?
原代码
#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); }
编译报错信息
Clang报错:
<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
GCC 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
问题原因及解决方案
原因分析
问题出在模板参数推导和概念约束的匹配上:
- 调用
test(engine)时,engine是左值,模板参数PRNG会被推导为左值引用类型std::minstd_rand&。 std::uniform_random_bit_generator概念要求的是生成器类型本身(而非引用类型),因为该概念需要访问生成器的静态成员函数min()和max(),但引用类型没有静态成员,导致约束检查失败。
解决方案
有两种常用的修复方式:
方式1:移除引用折叠,改用值传递或左值引用
如果希望接受左值生成器,可以将函数参数改为普通左值引用:
template<std::uniform_random_bit_generator PRNG> void test(PRNG & rng) { // 改为左值引用 std::uniform_int_distribution<int> dist{1, 7}; std::print("{}\n", dist(rng)); }
或者改用值传递(生成器通常是轻量级对象,拷贝成本低):
template<std::uniform_random_bit_generator PRNG> void test(PRNG rng) { // 值传递 std::uniform_int_distribution<int> dist{1, 7}; std::print("{}\n", dist(rng)); }
方式2:使用std::remove_reference_t调整概念约束
如果想保留完美转发的参数形式,需要在概念约束中去掉引用修饰:
template<typename PRNG> requires std::uniform_random_bit_generator<std::remove_reference_t<PRNG>> void test(PRNG && rng) { // 保留完美转发 std::uniform_int_distribution<int> dist{1, 7}; std::print("{}\n", dist(rng)); }
这样无论PRNG被推导为值类型还是引用类型,std::remove_reference_t都会剥离引用,检查原始生成器类型是否满足概念。
内容的提问来源于Stack Exchange,提问作者Xirema
相关产品推荐
相关产品推荐

