mercredi 13 mai 2015

ADL related GCC 4.7.2 issue with expression SFINAE

Take the following code, which is characterized by

  1. Reliance on ADL for a specific behavior (volume)
  2. Using decltype for return type and relying on SFINAE to discard extra 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 code as presented (without the template<class T> void volume() line), VS 2012 and clang 3.5 compiles 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 the extra template volume line, all three compile and run fine.

So, there is clearly a compiler defect here. My question is, which compiler is the defective one? And which C++ standard is being violated?

Aucun commentaire:

Enregistrer un commentaire