2015-05-14 75 views
3

採取下面的代碼,其特點是ADL相關GCC 4.7.2問題與表達SFINAE

  1. 依賴ADL爲特定行爲(volume
  2. 使用decltype用於返回類型和依託SFINAE丟棄額外重載
namespace Nature { 
    struct Plant {}; 
    double volume(Plant){ return 3.14; } 
} 

namespace Industrial { 
    struct Plant {}; 
    double volume(Plant) { return 100; } 
} 


namespace SoundEffects { 
    // A workaround for GCC, but why? 
    ////template<class T> void volume(); 

    template<class aSound> 
    auto mix(aSound& s) -> decltype(volume(s)*0.1) 
    { 
     return volume(s)*.1; 
    } 

    struct Samples { 
     Nature::Plant np; 
     Industrial::Plant ip; 
    }; 


    inline double mix(const Samples& s) { 
     return mix(s.np) + mix(s.ip); 
    } 
} 

int main() 
{ 
    SoundEffects::Samples s; 
    assert(mix(s) == 100*.1 + 3.14*.1); 
} 

的代碼提交(不template<class T> void volume()線),VS 2012和clang 3.5編譯成功,運行時間與預期一致。然而,GCC 4.7.2說:

template-function-overload.cpp: In substitution of 'template<class aSound> decltype ((volume(s) * 1.0000000000000001e-1)) SoundEffects::mix(aSound&) [with aSound = SoundEffects::Samples]': 
template-function-overload.cpp:46:4: required from here 
template-function-overload.cpp:23:9: error: 'volume' was not declared in this scope 
template-function-overload.cpp:23:9: note: suggested alternatives: 
template-function-overload.cpp:9:11: note: 'Nature::volume' 
template-function-overload.cpp:14:11: note: 'Industrial::volume' 

,具有額外template volume線,所有三個編譯和運行正常。

因此,這裏顯然存在編譯器缺陷。我的問題是,哪個編譯器是有缺陷的?哪個C++標準被違反?

+4

哪個版本的GCC?無法用4.8,4.9,5.1中的任何一個來重放 –

回答

2

這是一個自GCC 4.8以來修復的錯誤。下面是給出了同樣的錯誤代碼的simplified version

template<class T> 
auto buzz(T x) -> decltype(foo(x)); 

void buzz(int); 

int main() { 
    buzz(5); // error: 'foo' was not declared in this scope 
} 

mix(s)SoundEffects::mix兩個重載被編譯成通過ADL的候選重載(SoundEffectsSoundEffects::Sample相關的命名空間)。功能模板過載評估可行性。發生該錯誤是因爲volume(s)無法通過純粹的非限定查找或ADL for Sample解析爲合適的重載。

這之所以應該通的是,當查找失敗應該發生的取代失敗(因爲volume(s)依賴)和模板應從過載分辨率被拒絕。這將使mix(const Sample&)成爲唯一可行的超載選擇。有一個硬錯誤的事實顯然表明這個GCC版本的SFINAE實現有問題。