2017-04-07 26 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的隨機引擎所要做的。

總之,您不允許臨時綁定到非常量左值引用。當你這樣做的時候,這是一個錯誤。當你有一個參數既可以被讀取也可以被寫入,並且寫入的值很重要時,它是由非常量左值參考取得的,以便阻止你隨便傳遞一個臨時值並且讓寫入它的數據丟失了。

發電機是有狀態的。你想保留一個,並重復應用分配。

相關問題