2014-03-19 71 views
6

以下示例(ideone)在Windows 7上使用Visual Studio 2013时编译和工作,但在Ubuntu 13.10上不支持g ++ 4.8.1。为什么使用Visual Studio 2013编译而不是g ++ - 4.8.1?

#include <cassert> 
#include <cstdlib> 

#include <array> 
#include <iostream> 
#include <numeric> 
#include <utility> 

// Wraps a std::array of TKey/TValue pairs and provides a method 
// to randomly select a TKey with TValue bias. 
template< typename TKey, typename TValue, std::size_t TSize > 
class weights final 
{ 
    public: 
     using pair = const std::pair< const TKey, const TValue >; 
     using array = const std::array< pair, TSize >; 

     weights(array values) 
      : values_{ values } 
      , sum_{ std::accumulate(values_.begin(), values_.end(), 0, [](TValue total, const pair& p){ return total + p.second; }) } 
     {} 

     // Implements this algorithm 
     // http://stackoverflow.com/a/1761646/331024 
     const TKey get() const 
     { 
      // The real code uses c++11 <random> features, 
      // which I've removed for brevity. 
      auto weight_rand = static_cast<TValue>(std::rand() % sum_); 

      for (std::size_t i = 0; i < TSize; ++i) 
      { 
       if (weight_rand < values_[i].second) 
       { 
        return values_[i].first; 
       } 
       weight_rand -= values_[i].second; 
      } 
      assert(false); 
     } 

    private: 
     array values_; 
     const TValue sum_; 
}; 

enum class direction 
{ 
    NORTH, 
    SOUTH, 
    EAST, 
    WEST 
}; 

// For convenience create a type to map the above 
// four-value enumeration to integer weights. 
using w4i = weights< direction, int, 4 >; 

// Map the directions with a weight. 
static const w4i direction_weights = w4i::array{ 
    { 
     w4i::pair{ direction::NORTH, 2 }, 
     w4i::pair{ direction::EAST, 1 }, 
     w4i::pair{ direction::SOUTH, 3 }, 
     w4i::pair{ direction::WEST, 1 } 
    } 
}; 

int main() 
{ 
    std::cout << (int)direction_weights.get() << std::endl;  

    return 0; 
} 

Visual Studio 2013可以编译和运行代码。 g ++ - 4.8.1编译失败,输出如下错误:

$ g++ -std=c++11 -Wall -Wextra -pedantic weights.cpp -o weights 
weights.cpp: In instantiation of ‘weights<TKey, TValue, TSize>::weights(array) [with TKey = direction; TValue = int; long unsigned int TSize = 4ul; weights<TKey, TValue, TSize>::array = const std::array<const std::pair<const direction, const int>, 4ul>]’: 
weights.cpp:67:5: required from here 
weights.cpp:20:131: error: could not convert ‘values’ from ‘weights<direction, int, 4ul>::array {aka const std::array<const std::pair<const direction, const int>, 4ul>}’ to ‘const std::pair<const direction, const int>’, sum_{ std::accumulate(values_.begin(), values_.end(), 0, [](TValue total, const pair& p){ return total + p.second; }) } 

如何修改/修改它以使用两个编译器?

+0

FWIW后,也将其打开砰砰声3.4(相同/类似的错误)。将'values_'成员类型更改为'const array',或者在'using array' decl中丢失'const'。 – WhozCraig

+0

@WhozCraig感谢您的叮当反馈。我现在拥有的和你所建议的变化之间的功能区别是什么? –

+1

这是一些花哨的const正确性在行动中...和一些额外的'const'以防万一......以下情况下为 –

回答

7

你的问题是试图使用通用初始化,这引入了模糊性。以你的代码,并在创建小例子,结果:

不起作用:

struct weights 
{ 
    weights(std::array<int, 1> values) 
     : values_{values} 
    {} 

    std::array<int, 1> values_; 
}; 

作品:

struct weights 
{ 
    weights(std::array<int, 1> values) 
     : values_(values) 
    {} 

    std::array<int, 1> values_; 
}; 

的问题是,它变得模糊,以什么{values}应该做的。它应该创建一个包含一个元素的初始化列表(values)吗?或者它应该作为一个通用的初始化程序/括号 - 初始化和具有相同的行为括号?它看起来像GCC和叮当正在做第一次(这会导致类型不匹配),而Visual Studio正在做第二次(正确类型检查)。

如果您希望它在两者上均可使用,请使用括号。

我不知道这是GCC/clang或Visual Studio中的错误,还是标准中的歧义。

编辑:

对于一个简单的例子,考虑:

std::array<int, 2> a = {1, 2}; 
std::array<int, 2> b{a}; // error: no viable conversion from 'std::array<int, 2>' to 'value_type' (aka 'int') 
std::array<int, 2> b(a); // works 

首先是内部具有单一std::array<int, 2>对象创建初始化列表,而第二个被正确地调用拷贝构造函数。

+0

它看起来像一个库问题。相同的语法适用于std :: vector。 –

+0

@ nm:我提交了[llvm/libC++ bug](http://llvm.org/bugs/show_bug.cgi?id=19192)和[gcc/libstdC++ bug](http://gcc.gnu .ORG/bugzilla的/ show_bug.cgi?ID = 60592)。 – Cornstalks

+0

@ n.m。 'vector'不是一个聚合,所以适用不同的规则。我很确定这是DR1467,而VC++是一个错误的人。 –

3

这不是std::array

struct array { 
    int i; 
}; 

int main() 
{ 
    array a; 
    array b{a}; 
} 

g的错误++和锵都拒绝此,因为它们是由标准的要求,参见DR 1467我报GCC PR 51747

相关问题