ADL与表达SFINAE相关的GCC 4.7.2问题

时间:2015-05-14 01:39:58

标签: c++ templates c++11 argument-dependent-lookup

采用以下代码,其特征为

  1. 依赖ADL获取特定行为(WHERE `login` = 'name'
  2. 使用decltype作为返回类型并依赖SFINAE来丢弃额外的重载
  3. volume

    显示的代码(没有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 ); } 行),VS 2012和clang 3.5成功编译,运行时是预期的。但是,GCC 4.7.2说:

    template<class T> void volume()

    使用额外的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' 行,所有三个编译并运行正常。

    所以,这里显然存在编译器缺陷。我的问题是,哪个编译器是有缺陷的?哪个C ++标准被违反了?

1 个答案:

答案 0 :(得分: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)无法通过纯粹的非限定查找或Sample的ADL解析为合适的重载。

传递的原因是,当查找失败时,应发生替换失败(因为volume(s)依赖),并且应该从重载解析中拒绝模板。这将使mix(const Sample&)成为唯一可行的重载选择。存在严重错误的事实显然表明此GCC版本的SFINAE实施有缺陷。