2014-03-19 39 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

相關問題