ADL related issue in GCC 4.7.2 with SFINAE expression

Take the following code, which is characterized by

  • Reliance on ADL for specific behavior ( volume

    )
  • Using decltype for the return type and using SFINAE to avoid additional overloads
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 );
}

      

The presented code (no line template<class T> void volume()

), VS 2012 and clang 3.5 compile successfully and runtime is as expected. However, GCC 4.7.2 says:

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'

      

With an extra line, template volume

all three compile and execute fine.

So, there are clearly disadvantages of the compiler here. My question is which compiler is the defective one? And which C ++ standard is violated?

+3


source to share


1 answer


This was a bug that was fixed as of GCC 4.8 . Here's a simplified version of the code that gives the same error:

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
}

      



In mix(s)

both overload SoundEffects::mix

compiled into a set of candidates congestion through the ADL ( SoundEffects

- is associated namespace SoundEffects::Sample

). Function template overloading is evaluated for viability. The error occurs because it volume(s)

cannot be resolved to a suitable overload either with a pure unqualified lookup or with ADL for Sample

.

The reason this should happen is because if the lookup fails, a replace error is thrown (because it volume(s)

depends) and the template should be rejected from overload resolution. This would leave the mix(const Sample&)

only viable overload for choice. The fact that there is a hard bug is clearly a sign that this version of GCC has a faulty SFINAE implementation.

+2


source







All Articles