2013-05-02 2 views
1

클래스 생성자에 전달 된 데이터를 사용하여 std::discrete_distribution 개체를 만들려고합니다. 정적 데이터를 사용하여이를 만드는 방법을 알고 있지만 변수 데이터를 사용하는 방법을 알지 못합니다 (깔끔하게). 내가 지금 가지고있는 것은 "일"하지만 고통 스럽다. 이 작업을 수행하는 데 더 적합한 방법이 있습니까?변수 데이터에서 std :: initializer_list를 만드는 방법

distInit = { distArray[0], ... }; 라인이 문제입니다.

#include <iostream> 
#include <iomanip> 
#include <initializer_list> 
#include <map> 
#include <random> 

class Die { 
    private: 
     int loadSide; 
     double loadAmount; 
     std::mt19937 generator; 
     std::discrete_distribution<> distribution; 
     std::initializer_list<double> distInit; 
     std::array<double, 7> distArray; 
    public: 
     Die(int loadSide, double loadAmount) : loadSide(loadSide), loadAmount(loadAmount) { 
      distArray.fill(1); 
      distArray[0] = 0; 
      distArray[this->loadSide] = this->loadAmount; 

      distInit = { distArray[0], distArray[1], distArray[2], distArray[3], distArray[4], distArray[5], distArray[6] }; 
      distribution.param(distInit); 
     }; 
     int roll() { 
       return distribution(generator); 
     }; 
}; 

const int ROUNDS = 10000; 

int main() { 
    Die* die = new Die(5, 20); 

    std::map<int, int> m; 
    for(int n=0; n < ROUNDS; n++) { 
     m[die->roll()]++; 
    } 
    for(auto p : m) { 
     std::cout << p.first << " generated " << std::setiosflags(std::ios::fixed) << std::setprecision(2) << (float) p.second/ROUNDS << " times\n"; 
    } 
} 

올바른 질문을하지 않을 수도 있습니다. 사전에 사과드립니다. 이것은 내가이 주제에 대해 (분명히) 관련 히트를 찾을 수 없다는 것에 놀랐 기 때문에 강한 가능성이 있습니다.

제 컴파일러는 g++-mp-4.8 (MacPorts gcc48 4.8-20130411_0) 4.8.1 20130411 (prerelease)

명령 줄 /opt/local/bin/g++-mp-4.8 -std=c++11 test.cpp -o test

답변

2

, 사용되어야한다 discrete_distribution constructor taking a pair of iterators :

template< class InputIt > 
discrete_distribution(InputIt first, InputIt last); 

직접 param_type를 구성하려고해서는 안된다; 대신 도우미 함수를 사용하여 배포를 구성하십시오.

class Die { 
    private: 
     std::mt19937 generator; 
     std::discrete_distribution<> distribution; 
     static std::discrete_distribution<> makeDistribution(
      int loadSide, double loadAmount) 
     { 
      std::array<double, 7> distArray; 
      distArray.fill(1); 
      distArray[0] = 0; 
      distArray[loadSide] = loadAmount; 
      return {std::begin(distArray), std::end(distArray)}; 
     } 
    public: 
     Die(int loadSide, double loadAmount) : 
      generator{ }, 
      distribution{ makeDistribution(loadSide, loadAmount) } 
     {} 
     int roll() { 
       return distribution(generator); 
     } 
}; 
+0

한숨 ... 나는 심지어 생성자를 보지도 못했고 그것이 도움이되지는 않았다. 나는 유니폼 초기화를보고 그것을 이해해야 할 것이다. (C++을 사용한 이후로 길었었다.) 나는 makeDistribution이'std :: discrete_distribution' 타입을 반환하는 것을 이해하지 못합니다. 더 많은 연구. 도와 주셔서 감사합니다. – Rob

0

나는 OP에 표시된 것 이외의 std::array 같은 컨테이너에서 std::initializer_list을 만들 수있는 더 좋은 방법을 모르는 것입니다.

그러나 원래 문제, 즉 매개 변수를 배포에 전달하는 경우 좀 더 간단하게 제안 할 수 있습니다.

typedef std::discrete_distribution<>::param_type param_type; 
    distribution.param(param_type(distArray.begin(), distArray.end())); 

이 표준 배포판 (param() 촬영 인수의 유형입니다)하지만 지정하지 않는 형태의 멤버 param_type를 제공해야한다는 것을 말한다. 그러나, [rand.req.dist 상기 분포의 매개 변수에 대응하는 인자를 고려 D [분산 형]의 생성자의 각각에

는, P는 [param_type 상기에 대응 생성자 피사체를 가진다 말한다 동일한 요구 사항과 동일한 인수를 숫자, 유형 및 기본값으로 과 동일하게 사용합니다.

글쎄, std::discrete_distribution<>에는 매개 변수의 범위를 가리키는 반복자를 사용하는 생성자가 있습니다. 따라서 std::discrete_distribution<>::param_type이 무엇이든간에 비슷한 생성자가 있어야합니다. 따라서 param_typedistArray.begin()distArray.end()에서 생성하고 distribution.param()으로 전달하는 것이 좋습니다.

사이드 노트 : 더 이상 클래스에 std::initializer_list<double> distInit;이 필요하지 않습니다. 제게는 std::array<double, 7> distArray을 클래스 멤버로 필요로하지 않는다는 것입니다 (Die의 생성자에있는 로컬 변수 일 수 있음).

+0

Ahhh. 나는 어느 시점에서 반복기를 시험해 보았고 비어있는 상태가되었다. 나는 그것을'std :: discrete_distribution <> :: param_type'으로 던지지 않았다. 도와 주셔서 감사합니다. – Rob

+0

@Rob : 도움이 돼서 기쁩니다. 특정 상황에서 [솔루션] (http://stackoverflow.com/a/16355745/1137388) [ecatmur] (http://stackoverflow.com/users/567292/ecatmur)의 즉, 생성자는 실제로 내 것보다 우수합니다. 그러나 이미 작성된 배포판의 매개 변수를 변경해야 할 때 내 인수가 사용됩니다. –

+0

예, 귀하의 평가에 100 % 동의합니다. 나는 나의 진정한 요구 사항을 정확하게 말하지 않았으며 오히려 내가 필요하다고 생각했다. – Rob

0

std::initializer_list은 임시 개체 (함수 인수) 또는 로컬 변수로 사용하기위한 것입니다. 그것은 컨테이너가 아니며 아무것도 소유하지 않습니다. 익명의 임시 배열에 대한 접근 자입니다.

initializer_list 객체가 생성자의 ctor에-이니셜 라이저에서 초기화 언급, 그래서 배열 생성자가 종료 될 때까지 만 지속 표준은 코드와 유사한 예제를 포함

, §8.5.4/6, 따라서 생성자가 종료 된 후에 i4의 요소를 사용하면 정의되지 않은 동작이 발생합니다.

귀하의 경우에는 본문 앞의 ctor-initializer가 아닌 생성자 본문이지만 이야기는 같습니다.프로그램이 지금 일하는 것은 단지 바보 같은 일입니다.

개체에 분포를 저장하려면 std::array 또는 std::vector을 사용하십시오. array이 더 효율적이지만 arr = { … } 구문을 지원하지 않습니다. (몇 가지 간단한 대안이 있습니다.) vector은 중괄호와 = 연산자를 사용하여 구문을 지원합니다. 이 지원에서는 내재적 인 std::initializer_list을 사용합니다. 당신이 변수 데이터가있는 경우

+0

그래서 덤프 부분을 이해하지만 구현 한 것의 행운은 어디 있습니까? 나는 initializer_list를 올바르게 만들고있다. 어쩌면 당신은 클래스 변수'distArray' (필요 없음) 때문에 배포본을 변경하려고한다고 생각할 수 있습니까? 의도가 아니라, 잘못 배치되었습니다. – Rob

+0

'std :: array'는 C++ 11의'23.3.2.1/2'에 따라 명시 적으로 집계 초기화 구문을 지원하므로'arr = {...}'유형의 항목에 사용될 수 있습니다 ... [GCC 4.7] (http://ideone.com/CSboGR)은 그렇게하기를 꺼 렸지만 [GCC 4.8] (http://coliru.stacked-crooked.com/view?id=4d32ad1bc3a48af8722514ef8c48722f-50d9cfc8a1d350e7409e81e87c2653ba)이 괜찮습니다. – rubenvb

+0

@rob 올바르게 구성되지 않았습니다. initializer_list는 배열에 대한 두 개의 포인터로 구성되며,이 배열은 지역 변수 일뿐입니다. 그것은 생성자가 종료 될 때까지 지속되고, 그 후에 포인터는 매달리고 있습니다. – Potatoswatter

관련 문제