2017-04-07 111 views
2

我一直在通过Bjarne Stroustrup的“C++游览”学习C++ 11。为什么在这种情况下创建临时实例不起作用?

我的代码

#include <random> 
#include <functional> 

int main(int argc, char *argv[]) 
{ 
    using namespace std; 
    std::default_random_engine generator; 
    std::uniform_int_distribution<int> distribution {1,6}; 
    distribution(generator); //Case 1 works 

    auto die = bind(uniform_int_distribution<>{1,6},default_random_engine{}); //Case 2 works 

    distribution(std::default_random_engine{});  //Case 3 Compiler error 
} 

案例3是我自己创作的,而案件2来自书本和案例1我改编自别处下面的代码片段。 为什么case 3在下面产生编译器错误? 据我了解,情况1和情况3之间的唯一区别是,我使用std :: default_random_engine的一个临时实例,并且此临时实例似乎在情况下工作2 我错过了什么?

错误输出:

random.cpp: In function ‘int main(int, char**)’: 
random.cpp:13:46: error: no match for call to ‘(std::uniform_int_distribution<int>) (std::default_random_engine)’ 
    distribution(std::default_random_engine{});  //Case 3 Compiler error 
              ^
In file included from /usr/include/c++/6.3.1/bits/random.h:35:0, 
       from /usr/include/c++/6.3.1/random:49, 
       from random.cpp:1: 
/usr/include/c++/6.3.1/bits/uniform_int_dist.h:164:2: note: candidate: std::uniform_int_distribution<_IntType>::result_type std::uniform_int_distribution<_IntType>::operator()(_UniformRandomNumberGenerator&) [with _UniformRandomNumberGenerator = std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>; _IntType = int; std::uniform_int_distribution<_IntType>::result_type = int] <near match> 
    operator()(_UniformRandomNumberGenerator& __urng) 
    ^~~~~~~~ 
/usr/include/c++/6.3.1/bits/uniform_int_dist.h:164:2: note: conversion of argument 1 would be ill-formed: 
random.cpp:13:23: error: invalid initialization of non-const reference of type ‘std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>&’ from an rvalue of type ‘std::default_random_engine {aka std::linear_congruential_engine<long unsigned int, 16807ul, 0ul, 2147483647ul>}’ 
    distribution(std::default_random_engine{});  //Case 3 Compiler error 
         ^~~~~~~~~~~~~~~~~~~~~~~ 
In file included from /usr/include/c++/6.3.1/bits/random.h:35:0, 
       from /usr/include/c++/6.3.1/random:49, 
       from random.cpp:1: 
/usr/include/c++/6.3.1/bits/uniform_int_dist.h:169:2: note: candidate: template<class _UniformRandomNumberGenerator> std::uniform_int_distribution<_IntType>::result_type std::uniform_int_distribution<_IntType>::operator()(_UniformRandomNumberGenerator&, const std::uniform_int_distribution<_IntType>::param_type&) [with _UniformRandomNumberGenerator = _UniformRandomNumberGenerator; _IntType = int] 
    operator()(_UniformRandomNumberGenerator& __urng, 
    ^~~~~~~~ 
/usr/include/c++/6.3.1/bits/uniform_int_dist.h:169:2: note: template argument deduction/substitution failed: 
random.cpp:13:46: note: candidate expects 2 arguments, 1 provided 
    distribution(std::default_random_engine{});  //Case 3 Compiler error 
              ^
+7

您不能将可变引用绑定到临时对象。案例3试图做到这一点 – Justin

+4

检查例如[this'uniform_int_distribution :: operator()'引用](http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution/operator%28%29)。分布的参数是一个非常量引用,临时对象不能被这些引用绑定。 –

+0

谢谢!所以在方法需要const引用的情况下,我可以使用case 3的形式? – Avatar33

回答

1
distribution(generator); 

distribution修改的generator状态,并提取一个值。在接下来的调用,它返回一个不同的值,使用相同的generator

auto die = bind(uniform_int_distribution<>{1,6},default_random_engine{}); 

在这里,我们复制既是uniform_int_distribution<>{1,6}default_random_engine{}到绑定函数对象。在()它通过operator()通过default_random_engine{}uniform_int_distribution<>{1,6}uniform_int_distribution<>{1,6}修改default_random_engine{}的状态,并在下一次调用时返回不同的值,因为它使用(现在已修改)的生成器。

distribution(std::default_random_engine{}); 

这里您试图将random_engine&绑定到临时对象。 distribution想要修改随机引擎的状态,这就是为什么它是通过引用。

通过临时通过,任何此类更改将立即丢​​弃。不小心做到这一点很容易,搞砸了,所以默认情况下C++不允许你将一个临时对象绑定到一个非const的左值引用。

C++ std的设计者想要这个错误,所以他们通过非const的左值引用进行发布。它试图告诉你“这是一个糟糕的计划”。

你可以解决它:

template<class T> 
T& as_lvalue(T&& t){ return t; } 

现在

distribution(as_lvalue(std::default_random_engine{})); 

骗过编译器以为传入的default_random_engine一个临时的。它在线路末端仍然消失,并且由分配仔细完成的对发电机状态的修改被丢弃。

这通常是而不是当生成伪随机对象时,这就是C++ 11的随机引擎所要做的。

总之,您不允许临时绑定到非常量左值引用。当你这样做的时候,这是一个错误。当你有一个参数既可以被读取也可以被写入,并且写入的值很重要时,它是由非常量左值参考取得的,以便阻止你随便传递一个临时值并且让写入它的数据丢失了。

发电机是有状态的。你想保留一个,并重复应用分配。

相关问题