【问题标题】:ADL related GCC 4.7.2 issue with expression SFINAEADL 相关的 GCC 4.7.2 问题与表达式 SFINAE
【发布时间】:2015-05-14 01:39:58
【问题描述】:

取如下代码,其特点是

  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&lt;class T&gt; 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++ 标准?

【问题讨论】:

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


    【解决方案1】:

    这是一个自 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&amp;) 成为唯一可行的重载选择。存在硬错误这一事实显然表明此 GCC 版本的 SFINAE 实现存在错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-18
      相关资源
      最近更新 更多