2015-05-14 13 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实现有问题。