2017-04-07 1 views
2

Ich habe C++ 11 durch Bjarne Stroustrups "A Tour of C++" gelernt.Warum funktioniert das Erstellen einer temporären Instanz in diesem Fall nicht?

Ich habe den folgenden Code-Snippet

#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 
} 

Fall 3 ist meine eigene Kreation während Fall 2 aus dem Buch und Fall kommt 1 I aus anderen Ländern angepasst. Warum erzeugt Fall 3 den folgenden Compilerfehler? Soweit ich verstehe, der einzige Unterschied zwischen Fall 1 und Fall 3 ist, dass ich eine temporäre Instanz von std :: default_random_engine verwenden und diese temporäre Instanz scheint in Fall 2 zu funktionieren Was fehlt mir?

Fehlerausgang:

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

Sie können eine veränderbare Referenz nicht an eine temporäre Bindung binden. Fall 3 versucht dies zu tun – Justin

+4

Überprüfen Sie z.B. [Diese 'uniform_int_distribution :: operator()' Referenz] (http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution/operator%28%29). Das Argument für die Verteilung ist eine nicht konstante Referenz, und temporäre Objekte können nicht durch solche Referenzen gebunden werden. –

+0

Danke! Also, in dem Fall, in dem Methode eine Const-Referenz verwendet, wäre ich in der Lage, die Form von Fall 3 zu verwenden? – Avatar33

Antwort

1
distribution(generator); 

distribution modifiziert den Zustand des generator und extrahiert einen Wert. Beim nächsten Aufruf, gibt es einen anderen Wert, die gleichen generator

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

Hier verwenden, kopieren wir ein sowohl uniform_int_distribution<>{1,6} und ein default_random_engine{} in das bind Funktionsobjekt. Auf () übergibt es die default_random_engine{} an die uniform_int_distribution<>{1,6} über operator(). Die uniform_int_distribution<>{1,6} ändert den Zustand der default_random_engine{} und beim nächsten Aufruf gibt es einen anderen Wert zurück, da es den (jetzt geänderten) Generator verwendet.

distribution(std::default_random_engine{}); 

Hier versuchen Sie, eine random_engine& an ein temporäres Objekt zu binden. Die distribution möchte den Zustand der Random-Engine ändern, weshalb es als Referenz verwendet wird.

Durch das Übergeben einer temporären, würde jede solche Änderung sofort verworfen werden. Es ist leicht, dies versehentlich zu tun und zu vermasseln, so dass C++ standardmäßig nicht erlaubt, ein temporäres Objekt an eine nicht-konstante lvalue-Referenz zu binden.

Die Entwickler von C++ - Standard wollten diesen Fehler, also nahmen sie ihre Verteilung durch nicht-konstante Lvalue-Referenz. Es versucht dir zu sagen "das ist ein schlechter Plan".

Sie können es umgehen:

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

jetzt

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

täuscht den Compiler zu denken, dass die default_random_engine in nicht vorübergehend vergangen ist. Es verschwindet immer noch am Ende der Zeile und die durch die Verteilung sorgfältig vorgenommene Änderung des Generatorzustandes wird verworfen.

Dies ist in der Regel nicht was Sie wollen, wenn Pseudozufallsobjekte generieren, was C++ 11 zufällige Maschine ist.

Kurz gesagt, Sie sind nicht berechtigt, Provisorien an nicht konstante lvalue Referenzen zu binden. Wenn Sie dies tun, ist dies ein Fehler.Wenn Sie einen Parameter haben, der sowohl gelesen als auch geschrieben werden soll und der geschriebene Wert wichtig ist, wird er von einer nicht konstanten lvalue-Referenz übernommen, um zu verhindern, dass Sie zufällig eine temporäre übergeben und die haben Daten, die darauf geschrieben wurden, verloren.

Generatoren sind zustandsbehaftet. Sie möchten eines behalten und wiederholt eine Verteilung darauf anwenden.

Verwandte Themen