VC8 no ADL in some cases

Hi , I thought I'd download and try out VC8 . (Actual version at the bottom of post), however when used on my Tentative Boost quantities library, if I Use expressions on quantities at global function body scope(IOW functions not in boost::pqs namespace ) it complains that : : error C2676: binary '-' : 'const boost::pqs::t1_quantity<AbstractQuantity,Units,Value_type>' does not define this operator or a conversion to a type acceptable to the predefined operator with [ AbstractQuantity=boost::pqs::meta::components::of_velocity::type, Units=boost::pqs::meta::si_unit::none, Value_type=boost::pqs::quantity_traits::default_value_type ] (operator - is defined in same namespace as the type however.) The current workaround is just to define the operators in global namespace for this compiler( I know its not legal! but it gets around the problem). I'm wondering if anyone else has found this sort of problem in VC8.0? OTOH If there may be some reason , some two-phase lookup rule or something that is preventing these operations being found. (It seems simple to me. The types are defined in namespace boost::pqs. The operations on them are defined in boost::pqs. Whats the problem?) Note: I have tried to get the effect with other simpler types with operators defined in their own namepace, but these compile ok . regards Andy Little Heres a sample program that exhibits the problem #include <boost/pqs/t1_quantity/types/out/velocity.hpp> #include <boost/pqs/t1_quantity/types/out/mass.hpp> #include <boost/pqs/t1_quantity/types/out/force.hpp> #include <boost/pqs/t1_quantity/types/out/time.hpp> boost::pqs::force::N Func( const boost::pqs::mass::kg & mass_in, const boost::pqs::velocity::mm_div_s & initial_veloc, const boost::pqs::velocity::m_div_s & final_veloc, const boost::pqs::time::s & t ) { boost::pqs::force::N result = mass_in * (final_veloc - initial_veloc) / t; return result; } int main() { boost::pqs::mass::kg mass(2); boost::pqs::velocity::m_div_s initial_velocity(9); boost::pqs::velocity::m_div_s final_velocity(10); boost::pqs::time::s time(10); std::cout << Func(mass,initial_velocity,final_velocity,time) <<'\n'; } FWIW compler version: Microsoft Visual Studio 2005 Version 8.0.50727.42 (RTM.050727-4200) Microsoft .NET Framework Version 2.0.50727 Installed Edition: VC Express Microsoft Visual C++ 2005 76542-000-0000011-00125 Microsoft Visual C++ 2005

Andy Little wrote:
The current workaround is just to define the operators in global namespace for this compiler( I know its not legal! but it gets around the problem).
"using namespace boost::pqs" (on the user side) won't help?
I'm wondering if anyone else has found this sort of problem in VC8.0?
There's no ADL in BOOST_TYPEOF_TPL with MSVC8 (at least in some contexts, see http://tinyurl.com/7e6a6 -- the lack of ADL is only mentioned in a sidenote of the code, the thread is actually about even weirder MSVC8 behaviour in this context). Regards, Tobias

"Tobias Schwinger" wrote
Andy Little wrote:
The current workaround is just to define the operators in global namespace for this compiler( I know its not legal! but it gets around the problem).
"using namespace boost::pqs" (on the user side) won't help?
I'm wondering if anyone else has found this sort of problem in VC8.0?
There's no ADL in BOOST_TYPEOF_TPL with MSVC8 (at least in some contexts, see http://tinyurl.com/7e6a6 -- the lack of ADL is only mentioned in a sidenote of the code, the thread is actually about even weirder MSVC8 behaviour in this context).
I have just been reading n1792 "A modest proposal fixing ADL". In it Herb Sutter states that only two compilers of those tried VC8 and Com4.3.3 do ADL correctly, so maybe this is behind your problems. Having said that I have put my types and their operations in the same namespace as recommended in the paper (though I havent practisd the 'defensive programming' mentioned there), and I'm still getting errors. regards Andy Little

Andy Little wrote:
"Tobias Schwinger" wrote
Andy Little wrote:
I'm wondering if anyone else has found this sort of problem in VC8.0?
There's no ADL in BOOST_TYPEOF_TPL with MSVC8 (at least in some contexts, see http://tinyurl.com/7e6a6 -- the lack of ADL is only mentioned in a sidenote of the code, the thread is actually about even weirder MSVC8 behaviour in this context).
I have just been reading n1792 "A modest proposal fixing ADL". In it Herb Sutter states that only two compilers of those tried VC8 and Com4.3.3 do ADL correctly, so maybe this is behind your problems.
It definitely isn't - the case cited is much clearer than the one in the article. Further, ADL *is* working correctly on the same operator and the same types in a different context. Herb Sutter may or may not know that bug, however, it might not be appropriate for him to publicly highlight bugs of his employer's product. You wanted to know situations where ADL fails to work with VC8 -- well, here is one. Analyse the code if you have to see it with your own eyes ;-). Regards, Tobias

"Tobias Schwinger" wrote Andy Little wrote
I have just been reading n1792 "A modest proposal fixing ADL". In it Herb Sutter states that only two compilers of those tried VC8 and Com4.3.3 do ADL correctly, so maybe this is behind your problems.
It definitely isn't - the case cited is much clearer than the one in the article. Further, ADL *is* working correctly on the same operator and the same types in a different context.
Sorry about that. I've been going round and round trying to find out what I did wrong, but this time it does seem that I am right that the compiler is wrong ... so to speak. If so its very disappointing. I had been looking forward to using VC8
Herb Sutter may or may not know that bug, however, it might not be appropriate for him to publicly highlight bugs of his employer's product.
You wanted to know situations where ADL fails to work with VC8 -- well, here is one. Analyse the code if you have to see it with your own eyes ;-).
I tried out the example. VC8 doesnt seem to like operator + much does it? or - / * for that matter. What should be done about it. Should someone start reporting this to the folks at Microsoft or what? regards Andy Little

Andy Little wrote:
"Tobias Schwinger" wrote Andy Little wrote
I have just been reading n1792 "A modest proposal fixing ADL". In it Herb Sutter states that only two compilers of those tried VC8 and Com4.3.3 do ADL correctly, so maybe this is behind your problems.
It definitely isn't - the case cited is much clearer than the one in the article. Further, ADL *is* working correctly on the same operator and the same types in a different context.
Sorry about that. I've been going round and round trying to find out what I did wrong, but this time it does seem that I am right that the compiler is wrong ... so to speak. If so its very disappointing. I had been looking forward to using VC8
I'm sure it can be worked around (the one way or the other).
I tried out the example. VC8 doesnt seem to like operator + much does it? or - / * for that matter.
Well, we're talking about two (probably closely related) bugs here: 1) The deduction in boost::spirit::operator+ fails (which can -for some odd reason- be worked around by overloading the operator). 2) ADL doesn't work. When using the commented line (instead of "using namespace...") in this part // using boost::spirit::anychar_p; using namespace boost::spirit; // ADL doesn't seem to work, either but I could live with this problem ;-) of the code, the operator isn't found at all. The commented line is perfectly enough in the non-templated case, though (the case you get if MAKE_THINGS_FAIL is not defined). Also note that these problems are not limited to operators -- they applly to functions in general.
What should be done about it. Should someone start reporting this to the folks at Microsoft or what?
Definitely. But we should first minimize the case and try to find out what exactly causes VC8 to turn off ADL (the same situation probably also activates bug1, above). How does the declaration of your operator- look like? Does it instantiate templates that use sizeof- or conditional tricks (as BOOST_TYPEOF_TPL does)? There must be /something/ going on, because for "pure expression templates" (e.g. Spirit without Typeof) ADL works fine. There would be problems with other Boost libraries as well, I figure. Here's a suggestion for a rather pragmatic solution: // at root namespace #if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1400)) && BOOST_MSVC >= 1400 using [...] operator [...]; using [...] operator [...]; [...] #endif if that won't help, define the operators at root namespace for that compiler. Of course you should use restricted parameters rather than fully general templates that match everything: // This one means trouble when injected into the root namespace template<typename T0,typename T1> typename result<T0,T1>::type operator-(T0 const &, T1 const &); // This one should be mostly (because implicit conversion ctors in // boost::pqs::some_template could still cause trouble) harmless. template<typename T0,typename T1> typename result<T0,T1>::type operator-(boost::pqs::some_template<T0> const &, T1 const &); Regards, Tobias

"Tobias Schwinger" wrote
Andy Little wrote:
[...]
What should be done about it. Should someone start reporting this to the folks at Microsoft or what?
Definitely. But we should first minimize the case and try to find out what exactly causes VC8 to turn off ADL (the same situation probably also activates bug1, above).
How does the declaration of your operator- look like?
Here's operator +. (All operators fail in a similar way ) namespace boost{namespace pqs{ template < typename AbstractQuantity , typename UnitsL , typename Value_typeL , typename UnitsR , typename Value_typeR > inline typename meta::binary_operation< t1_quantity< AbstractQuantity , UnitsL , Value_typeL > , meta::plus , t1_quantity< AbstractQuantity , UnitsR , Value_typeR > >::type operator + ( t1_quantity< AbstractQuantity , UnitsL , Value_typeL > const & lhs , t1_quantity< AbstractQuantity , UnitsR , Value_typeR > const & rhs ) { typename meta::binary_operation< t1_quantity< AbstractQuantity, UnitsL , Value_typeL > , meta::plus , t1_quantity< AbstractQuantity , UnitsR , Value_typeR > >::type result = lhs; result += rhs; return result; } }} Heres one example. >
Does it instantiate templates that use sizeof- or conditional tricks (as BOOST_TYPEOF_TPL does)?
The pqs::meta::binary_operation result_type scheme in the operator+ definition above uses SFINAE quite heavily though. I shall try reducing it to a minimal example. Boost.Typeof use in the implementation (for operations on built-in types) is optional though I havent tried turning it off yet [... workaround] Ok I have opted to define in global namespace currently. regards Andy Little

It might have something to do with operations on temporaries in parentheses? Whatever heres more context to my other example example . Note if you want to try this out in pqs _3_0_4 you need to add boost::pqs:: in front of t1_quantity at line 143 In <boost/pqs/t1_quantity/operations/add_subtract.hpp>. Thats an error in pqs_3_0_4 but only affects VC8 Then in the same file disable the conditonal defines for vc8 around namespace open and close parentheses for operator + and operator - . Maybe this will work on simpler udts in the same sort of situation. Will try this next. #include <boost/pqs/t1_quantity/types/out/velocity.hpp> #include <boost/pqs/t1_quantity/types/out/acceleration.hpp> #include <boost/pqs/t1_quantity/types/out/time.hpp> // Note all operators except addition/subtraction // are defined in global namespace for this test // #define FUNC1 only --> compiles OK // #define FUNC1 and FUNC2 --> compiles OK // #define FUNC2 --> error no '-' operator found #define FUNC1 #define FUNC2 #ifdef FUNC1 boost::pqs::acceleration::m_div_s2 Func1( const boost::pqs::velocity::mm_div_s& a, const boost::pqs::velocity::m_div_s& b, const boost::pqs::time::s & t ) { // succeeds not affected by parentheses; boost::pqs::velocity::m_div_s v = (a - b); // succeeds //boost::pqs::velocity::m_div_s v = a - b; boost::pqs::acceleration::m_div_s2 result = v / t; return result; } #endif #ifdef FUNC2 boost::pqs::acceleration::m_div_s2 Func( const boost::pqs::velocity::mm_div_s & a, const boost::pqs::velocity::m_div_s& b, const boost::pqs::time::s & t ) { // fails boost::pqs::acceleration::m_div_s2 result = (a-b) / t; // fails // boost::pqs::acceleration::m_div_s2 result = 1 / (t / (a-b)); // succeeds //boost::pqs::acceleration::m_div_s2 result = (boost::pqs::operator-(a, b)) / t; // succeeds //boost::pqs::acceleration::m_div_s2 result = a / t - b/ t; return result; } #endif

Andy Little wrote:
"Tobias Schwinger" wrote
How does the declaration of your operator- look like?
Here's operator +. (All operators fail in a similar way )
[...code]
Your operator- (in the code of your initial post) is not the problem it must be the context it's used in. I got a copy of your lib and comented the workaround and operator- and added template<typename T0,typename T1> T0 operator-(T0 const &, T1 const &); and it didn't change anything.
Does it instantiate templates that use sizeof- or conditional tricks (as BOOST_TYPEOF_TPL does)?
The pqs::meta::binary_operation result_type scheme in the operator+ definition above uses SFINAE quite heavily though. I shall try reducing it to a minimal example.
SFINAE (at least SFINAE alone) is not the problem, either. I wrote this little test which compiles fine (it would have been too easy, I guess) ;-(. namespace user_namespace { // some class template template<typename T> struct t1 { }; // traits to detect its specializations template<typename T> struct is_t1 { static bool const value = false; }; template<typename T> struct is_t1<t1<T> > { static const bool value = true; }; // another class template template<typename T> struct t2 { }; // traits to detect its specializations template<typename T> struct is_t2 { static bool const value = false; }; template<typename T> struct is_t2<t2<T> > { static const bool value = true; }; // tool to create a sfinae condition if the first argument is false template<bool, typename T> struct enable_if { typedef T type; }; template<typename T> struct enable_if<false,T> { }; // function templates template<typename T> typename enable_if<is_t1<T>::value, T >::type outer(t1<T> const & v); template<typename T> typename enable_if<is_t2<T>::value, T >::type outer(t1<T> const & v); template<typename T> t1<T> inner(t1<T> const & v); } void func() { user_namespace::t1< user_namespace::t1<int> > x; user_namespace::t1< user_namespace::t2<int> > y; // 'inner' is found by ADL outer(inner(x)); outer(inner(y)); }
Boost.Typeof use in the implementation (for operations on built-in types) is optional though I havent tried turning it off yet
BOOST_TYPEOF_TPL in particular messes up ADL for the expression passed to it (the thread I linked to). Guessing from VC8's extremely strange behaviour in that case TYPEOF_TPL might act as some sort of "bug attractant"... I'd definitely give it a try! Hope it helps, Tobias

"Tobias Schwinger" wrote
Your operator- (in the code of your initial post) is not the problem it must be the context it's used in.
I got a copy of your lib and comented the workaround and operator- and added
template<typename T0,typename T1> T0 operator-(T0 const &, T1 const &);
and it didn't change anything.
Does it instantiate templates that use sizeof- or conditional tricks (as BOOST_TYPEOF_TPL does)?
The pqs::meta::binary_operation result_type scheme in the operator+ definition above uses SFINAE quite heavily though. I shall try reducing it to a minimal example.
SFINAE (at least SFINAE alone) is not the problem, either. I wrote this little test which compiles fine (it would have been too easy, I guess) ;-(.
[ cut code that fails to fail ] I tried something similar with no luck. Both my quantities library and Spirit have in common that types are complicated I think. Maybe this is the cause of the problem. Say where there is a large number of contexts to look up, the first or last one gets missed or overwritten. It might be worth sprinkling likely operations around in some other namespaces mentioned in 3.4.2 to see if there is any sign of two phase lookup occurring. Whatever my first strategy is going to be to strip back my pqs library bit by bit until the bug disappears. I feel better about that than building something waiting for the bug to appear. ;-)
Boost.Typeof use in the implementation (for operations on built-in types) is optional though I havent tried turning it off yet
BOOST_TYPEOF_TPL in particular messes up ADL for the expression passed to it (the thread I linked to). Guessing from VC8's extremely strange behaviour in that case TYPEOF_TPL might act as some sort of "bug attractant"... I'd definitely give it a try!
I have tried it but It makes no difference in this particular case. FWIW if you go into <boost/pqs/config.hpp> and comment out line 30 : #define BOOST_PQS_USE_BOOST_TYPEOF_BINARY_OPERATION . Then Boost.Typeof is knocked out ... though it adds in another synthesized type deduction scheme. regards Andy Little
participants (4)
-
Andy Little
-
Bronek Kozicki
-
David Abrahams
-
Tobias Schwinger