【问题标题】:Initialising std::discrete_distribution in VS2013在 VS2013 中初始化 std::discrete_distribution
【发布时间】:2014-03-24 10:36:08
【问题描述】:

我有一个包含权重列表的std::vector<float> weights;。在运行程序的某个阶段之前,我不知道此列表中会包含什么。我想做

std::discrete_distribution<> dist(weights.begin(),weights.end());

但是 VS2013 似乎没有接受迭代器范围的 std::discrete_distribution 构造函数。有什么解决方法吗?

【问题讨论】:

    标签: c++ c++11 visual-studio-2013 std c++-standard-library


    【解决方案1】:

    比较cppreference.comMicrosoft referencestd::discrete_distribution

    这些是VS2013提供的构造函数:

    discrete_distribution();
    explicit discrete_distribution(
        const param_type& par0
    );
    discrete_distribution(
        initializer_list<double> IList
    );
    template<class Fn>
        discrete_distribution(
            size_t count,
            double low, 
            double high, 
            Fn func
    );
    

    缺少一个重要的构造函数,可能是因为微软开发人员没有时间实现它:

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

    这意味着,除非文档不完整,否则您根本不能为此类使用基于迭代器的构造函数。切换到另一个编译器(如 clang 或 g++),或等到此功能实现。

    现在可以使用的解决方法:

    std::size_t i(0);
    assert( !weights.empty() ); // No weights would be very weird.
    std::discrete_distribution<> dist(weights.size(),
                                      0.0, // dummy!
                                      0.0, // dummy!
                                      [&weights,&i](double)
    {
       auto w = weights[i];
       ++i;
       return w;
     });
    

    我希望至少支持 lambdas ;-) 重要的是通过引用捕获 i,这样它就可以正确递增。演示:http://ideone.com/nIBUts

    为什么会这样?我们这里使用的构造函数是:

    template< class UnaryOperation >
    discrete_distribution( std::size_t count, double xmin, double xmax,
                           UnaryOperation unary_op );
    

    documentation on cppreference 告诉我们count(在我们的例子中为weights.size())以及xminxmax 用于使用UnaryOperation 创建权重。

    我们忽略 xminxmax 是故意的。作为UnaryOperation,我们使用lambda

    [&weights,&i](double)
    {
       auto w = weights[i];
       ++i;
       return w;
     }
    

    [&weights,&i](double)
    {
       return weights[i++];
    }
    

    如果你愿意的话。

    现在,我们忽略该运算符的输入值,只返回向量的第 i^th 个元素。我们通过引用捕获向量和索引以避免复制。

    【讨论】:

    • 也许我的问题不够清楚 - 我知道 VS2013 缺少这个基于迭代器的构造函数。我正在寻找某种解决方法,而不仅仅是切换编译器或等待。
    • @pighead10 查看我的编辑。这些方面的东西应该起作用。我还没有测试过(这台机器上没有编译器)。 [更新] 至少它可以用 g++-4.7 编译
    • 您可以将 lambda 简化为 [&amp;weights,&amp;i](double){ return weights[i++]; }
    • @Jaxan 我不认为这是一种改进/简化。是的,它的代码更少,但生成的机器将是相同的。因此,我遵循我个人的经验法则,即从不连续做一件以上的事情。对我来说,对元素的访问与迭代是分开的,因此应该将其分开以获得最大的清晰度。
    • 好的,这是一个口味问题,因为我发现您的代码有点混淆:它给我的印象是它做了很多,因为有 3 行。除此之外,我认为array[i++]*it++ = ... 经常出现,以至于人们非常清楚。感谢您的快速回复:)。
    【解决方案2】:
    std::discrete_distribution<> dist(
        weights.size(), 
        -0.5, 
        -0.5+weights.size(), 
        [&weights](size_t i) 
        { 
            return weights[i]; 
        });
    

    或者就迭代器而言:

    //replacement code for: std::discrete_distribution<> dist(first, last);
    auto first = weights.cbegin();
    auto last = weights.cend();
    auto count = std::distance(first, last);
    std::discrete_distribution<> dist(
        count, 
        -0.5, 
        -0.5+count, 
        [&first](size_t i) 
        { 
            return *std::next(first,i); 
        });
    

    这避免了必须捕获可变的i 变量。传递给 lambda 的参数可以用作索引。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      • 1970-01-01
      • 2013-03-22
      相关资源
      最近更新 更多