Workaround for compiler bugs

In attempting to write a library for Boost I have sometimes run into a given compiler's bug which prevents my work succeeding for a given compiler without a workaround. While I can, and have, gone to a compiler's NG or online forum to report the bug, and hopefully find a workaround, given the nature and difficulty of template metaprogramming there have often been no adequate responses. Of course I have worked to find a workaround on my own, but sometimes I can not find the "magic incantation" <g> to do so, while in other cases I can. Is this a valid NG for bringing such a compiler bug to light so that other Boost developers are not only aware of the bug but might have a solution, if they have not already developed one for themselevs ? Sometimes the bug peripherally involves some Boost library but often the bug just involves some sort of template, or template metaprogramming, construct which a particular compiler just can not handle correctly. In all cases the bug would have to do with some Boost-like library I am working on, preferably in the sandbox, else I would not feel justified in bringing up this issue in a Boost developer NG.

At Mon, 06 Dec 2010 09:06:19 -0500, Edward Diener wrote:
In attempting to write a library for Boost I have sometimes run into a given compiler's bug which prevents my work succeeding for a given compiler without a workaround. While I can, and have, gone to a compiler's NG or online forum to report the bug, and hopefully find a workaround, given the nature and difficulty of template metaprogramming there have often been no adequate responses. Of course I have worked to find a workaround on my own, but sometimes I can not find the "magic incantation" <g> to do so, while in other cases I can.
Is this a valid NG for bringing such a compiler bug to light so that other Boost developers are not only aware of the bug but might have a solution, if they have not already developed one for themselevs ?
Sometimes the bug peripherally involves some Boost library but often the bug just involves some sort of template, or template metaprogramming, construct which a particular compiler just can not handle correctly. In all cases the bug would have to do with some Boost-like library I am working on, preferably in the sandbox, else I would not feel justified in bringing up this issue in a Boost developer NG.
Gray area. I say, if you need help getting over a Boost-related hump, ask here. If it gets out of hand, moderators will step in. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

On 12/6/2010 10:10 AM, Dave Abrahams wrote:
At Mon, 06 Dec 2010 09:06:19 -0500, Edward Diener wrote:
In attempting to write a library for Boost I have sometimes run into a given compiler's bug which prevents my work succeeding for a given compiler without a workaround. While I can, and have, gone to a compiler's NG or online forum to report the bug, and hopefully find a workaround, given the nature and difficulty of template metaprogramming there have often been no adequate responses. Of course I have worked to find a workaround on my own, but sometimes I can not find the "magic incantation"<g> to do so, while in other cases I can.
Is this a valid NG for bringing such a compiler bug to light so that other Boost developers are not only aware of the bug but might have a solution, if they have not already developed one for themselevs ?
Sometimes the bug peripherally involves some Boost library but often the bug just involves some sort of template, or template metaprogramming, construct which a particular compiler just can not handle correctly. In all cases the bug would have to do with some Boost-like library I am working on, preferably in the sandbox, else I would not feel justified in bringing up this issue in a Boost developer NG.
Gray area. I say, if you need help getting over a Boost-related hump, ask here. If it gets out of hand, moderators will step in.
OK, understood. I have a possible candidate for a nasty compiler bug in VC++ concerning an area of C++ templates, but I want to work a little further on my own to see if I can find a workaround before I bring it up here. The bug is directly related to a library I have put in the sandbox, but have not yet announced although I will probably do so as soon as I get my tests and documentation finished.

On 1:59 PM, Edward Diener wrote:
On 12/6/2010 10:10 AM, Dave Abrahams wrote:
At Mon, 06 Dec 2010 09:06:19 -0500, Edward Diener wrote:
[...]
Is this a valid NG for bringing such a compiler bug to light so that other Boost developers are not only aware of the bug but might have a solution, if they have not already developed one for themselevs ?
[...]
Gray area. I say, if you need help getting over a Boost-related hump, ask here. If it gets out of hand, moderators will step in.
OK, understood. I have a possible candidate for a nasty compiler bug in VC++ concerning [...]
This seems like valuable input for boost.config. Could you adapt it as a patch & associated test(s)?

On 12/6/2010 2:53 PM, Jim Bell wrote:
On 1:59 PM, Edward Diener wrote:
On 12/6/2010 10:10 AM, Dave Abrahams wrote:
At Mon, 06 Dec 2010 09:06:19 -0500, Edward Diener wrote:
[...]
Is this a valid NG for bringing such a compiler bug to light so that other Boost developers are not only aware of the bug but might have a solution, if they have not already developed one for themselevs ?
[...]
Gray area. I say, if you need help getting over a Boost-related hump, ask here. If it gets out of hand, moderators will step in.
OK, understood. I have a possible candidate for a nasty compiler bug in VC++ concerning [...]
This seems like valuable input for boost.config. Could you adapt it as a patch& associated test(s)?
First of all, in the particular case which I am seeing, I do not have a workaround yet so there is no "patch" as I understand that you mean. Secondly the bug I am seeing may affect only what I am trying to do in the sandbox library and may never occur in whatever other area of Boost programming that exists, but still I do understand that having boost.config be aware of it under some sort of macro name might be valuable to Boost in general. Finally, although I can reproduce the bug within a certain well-defined context, the actual single construct where the bug is happening is still hard to define or reproduce, so a place where boost.config can identify the exact statement/construct in which the bug occurs is still elusive. But I will be trying to find a workaround and narrow down exactly why the bug is occuring as soon as I can. Since I have said so much about this situation, I should point anyone who might be interested in what I have uncovered in VC++ while trying to achieve a goal in my sandbox library to both my error report to Microsoft and my post on Microsoft's online forums regarding the situation. The error report to Microsoft is at https://connect.microsoft.com/VisualStudio/feedback/details/624757/incorrect... . The explanation and the attachment there should explain what is happening. Microsoft has not come back with much about it. I filed another similar bug report which I discovered, but for which I subsequently did find a workaround, at https://connect.microsoft.com/VisualStudio/feedback/details/618414/incorrect... and Microsoft's only response beside acknowledging the bug was to say, as usual, they will not fix it. So I have little hope that they will fix this later one sometime in the future, as ridiculous as both bugs are, but if I call them up they are supposed to find a workaround for me. I just do not want to call them up and enter the Microsoft merry-go-round of supplying the end-user with a workaround ( once it took them over 3 months ), until I absolutely have to do so. The report about this bug in the Microsoft online forums is at http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/8091f43b-56d... . A Microsoft moderator has responded about a week ago that he is looking at the issue, but I have heard nothing further from him, and somehow seriously doubt that he will find a workaround. Perhaps someone here on this forums will find a workaround, but they would need to test under VC9 and VC10 at least ( I haven't tried it yet but I am guessing the bug is probably present in VC8 and VC7.1 also ). Needless to say the bug does not occur under gcc 4.0+.

[Edward Diener]
https://connect.microsoft.com/VisualStudio/feedback/details/624757/incorrect...
Is this sufficient for your purposes? (Requires VC10.) C:\Temp>type meow.cpp #include <type_traits> #define DEFINE_HAS_MEMBER(NAME) \ template <typename T> class has_member_ ## NAME { \ private: \ template <typename U> static std::true_type helper(decltype(&U::NAME)); \ template <typename U> static std::false_type helper(...); \ public: \ typedef decltype(helper<T>(nullptr)) type; \ static const bool value = type::value; \ }; DEFINE_HAS_MEMBER(cMem) struct Gipf { }; struct Dvonn { Gipf cMem; }; struct Tzaar { bool cMem; }; struct Yinsh { int Zertz; }; int main() { static_assert(has_member_cMem<Dvonn>::value, "Dvonn"); static_assert(has_member_cMem<Tzaar>::value, "Tzaar"); static_assert(!has_member_cMem<Yinsh>::value, "Yinsh"); } C:\Temp>cl /EHsc /nologo /W4 meow.cpp meow.cpp C:\Temp> Stephan T. Lavavej Visual C++ Libraries Developer

On 12/6/2010 5:00 PM, Stephan T. Lavavej wrote:
[Edward Diener]
https://connect.microsoft.com/VisualStudio/feedback/details/624757/incorrect...
Is this sufficient for your purposes? (Requires VC10.)
C:\Temp>type meow.cpp #include<type_traits>
#define DEFINE_HAS_MEMBER(NAME) \ template<typename T> class has_member_ ## NAME { \ private: \ template<typename U> static std::true_type helper(decltype(&U::NAME)); \ template<typename U> static std::false_type helper(...); \ public: \ typedef decltype(helper<T>(nullptr)) type; \ static const bool value = type::value; \ };
You missed the fact in the attachment that the T passed in must be the full signature of a pointer to data member, as in 'Gipf Dvonn::*' in your first example below. Otherwise if you can get it to work in VC++, I would be most appreciative, although I do not know if I want to use the C++0x 'decltype' feature since the library theoretically needs to work with C++03 standard compliant compilers.
DEFINE_HAS_MEMBER(cMem)
struct Gipf { };
struct Dvonn { Gipf cMem; };
struct Tzaar { bool cMem; };
struct Yinsh { int Zertz; };
int main() { static_assert(has_member_cMem<Dvonn>::value, "Dvonn"); static_assert(has_member_cMem<Tzaar>::value, "Tzaar"); static_assert(!has_member_cMem<Yinsh>::value, "Yinsh"); }
C:\Temp>cl /EHsc /nologo /W4 meow.cpp meow.cpp
C:\Temp>

[Edward Diener]
You missed the fact in the attachment that the T passed in must be the full signature of a pointer to data member, as in 'Gipf Dvonn::*' in your first example below.
I wasn't sure if mentioning the data member's type was a desired feature of your code. Here's how to achieve that: C:\Temp>type meow.cpp #include <type_traits> #define DEFINE_HAS_MEMBER_OF_TYPE(NAME) \ template <typename T> class has_member_ ## NAME { \ private: \ template <typename U> static std::true_type helper(decltype(&U::NAME)); \ template <typename U> static std::false_type helper(...); \ public: \ typedef decltype(helper<T>(nullptr)) type; \ static const bool value = type::value; \ }; \ \ template <typename T, typename X, bool B> \ struct has_member_ ## NAME ## _of_type_helper \ : public std::false_type { }; \ \ template <typename T, typename X> \ struct has_member_ ## NAME ## _of_type_helper<T, X, true> \ : public std::is_same<decltype(&T::NAME), X T::*> { }; \ \ template <typename T, typename X> \ struct has_member_ ## NAME ## _of_type \ : public has_member_ ## NAME ## _of_type_helper< \ T, X, has_member_ ## NAME<T>::value> { }; DEFINE_HAS_MEMBER_OF_TYPE(cMem) struct Gipf { }; struct Dvonn { Gipf cMem; }; struct Tzaar { int cMem; }; struct Yinsh { int Zertz; }; int main() { static_assert( has_member_cMem_of_type<Dvonn, Gipf>::value, "one"); static_assert(!has_member_cMem_of_type<Dvonn, int>::value, "two"); static_assert(!has_member_cMem_of_type<Tzaar, Gipf>::value, "three"); static_assert( has_member_cMem_of_type<Tzaar, int>::value, "four"); static_assert(!has_member_cMem_of_type<Yinsh, Gipf>::value, "five"); static_assert(!has_member_cMem_of_type<Yinsh, int>::value, "six"); } C:\Temp>cl /EHsc /nologo /W4 meow.cpp meow.cpp C:\Temp> Note that these macros do not attempt to avoid the formation of Standard-forbidden double underscores when given data member names with leading or trailing underscores. (Conveniently, I hate such names.) STL

On 12/6/2010 7:43 PM, Stephan T. Lavavej wrote:
[Edward Diener]
You missed the fact in the attachment that the T passed in must be the full signature of a pointer to data member, as in 'Gipf Dvonn::*' in your first example below.
I wasn't sure if mentioning the data member's type was a desired feature of your code. Here's how to achieve that:
C:\Temp>type meow.cpp #include<type_traits>
#define DEFINE_HAS_MEMBER_OF_TYPE(NAME) \ template<typename T> class has_member_ ## NAME { \ private: \ template<typename U> static std::true_type helper(decltype(&U::NAME)); \ template<typename U> static std::false_type helper(...); \ public: \ typedef decltype(helper<T>(nullptr)) type; \ static const bool value = type::value; \ }; \ \ template<typename T, typename X, bool B> \ struct has_member_ ## NAME ## _of_type_helper \ : public std::false_type { }; \ \ template<typename T, typename X> \ struct has_member_ ## NAME ## _of_type_helper<T, X, true> \ : public std::is_same<decltype(&T::NAME), X T::*> { }; \ \ template<typename T, typename X> \ struct has_member_ ## NAME ## _of_type \ : public has_member_ ## NAME ## _of_type_helper< \ T, X, has_member_ ## NAME<T>::value> { };
Thanks ! I will look at this and see what I can do with it, but I have to achieve this without the use of 'decltype'. The obvious reason is that 'decltype' is C++0x and I will almost certainly target my library for C++ compilers which support only C++03 instead at the base level of use. Obviously I do not mind using C++0x features as long as a compiler supports them but if they do not, this should still be workable without them. Also, while VC++ 10 supports decltype, VC++ 9 and below does not and I need to get my library working with those earlier versions of VC++ also.

On 12/6/2010 7:43 PM, Stephan T. Lavavej wrote:
[Edward Diener]
You missed the fact in the attachment that the T passed in must be the full signature of a pointer to data member, as in 'Gipf Dvonn::*' in your first example below.
I wasn't sure if mentioning the data member's type was a desired feature of your code. Here's how to achieve that:
C:\Temp>type meow.cpp #include<type_traits>
#define DEFINE_HAS_MEMBER_OF_TYPE(NAME) \ template<typename T> class has_member_ ## NAME { \ private: \ template<typename U> static std::true_type helper(decltype(&U::NAME)); \
I quickly played around with this a little seeing if I could remove 'decltype'. Evidently the VC++ compiler can not handle: "template<typename U> static std::true_type helper(&U::NAME);" spitting out the message of 'error C2998: 'std::tr1::true_type helper' : cannot be a template definition' instead. While 'decltype' solves that problem for expressions of the type '&T::someVariablename' in template code in VC10, VC9 has the same problem and there, as I mentioned, there is no solution which I have been able to discover since 'decltype' does not exist in VC++ prior to the latest release. So as I mentioned I can use 'decltype' in VC10 for a solution but I am still without a solution for earlier versions of VC++. BTW, without the 'decltype' in your example code I do not see why the code is not valid. Care to explain why VC++ thinks it is necessary ? I can not imagine not being able to understand '&T::someVariablename' by a C++ compiler when T is known to be a type. I will continue to look for a workaround for VC9 and earlier, as I think my library should be usable by VC9, VC8, and perhaps VC7.1. Thanks for your neat solution for VC10 !
template<typename U> static std::false_type helper(...); \ public: \ typedef decltype(helper<T>(nullptr)) type; \ static const bool value = type::value; \ }; \ \ template<typename T, typename X, bool B> \ struct has_member_ ## NAME ## _of_type_helper \ : public std::false_type { }; \ \ template<typename T, typename X> \ struct has_member_ ## NAME ## _of_type_helper<T, X, true> \ : public std::is_same<decltype(&T::NAME), X T::*> { }; \ \ template<typename T, typename X> \ struct has_member_ ## NAME ## _of_type \ : public has_member_ ## NAME ## _of_type_helper< \ T, X, has_member_ ## NAME<T>::value> { };
DEFINE_HAS_MEMBER_OF_TYPE(cMem)
struct Gipf { };
struct Dvonn { Gipf cMem; };
struct Tzaar { int cMem; };
struct Yinsh { int Zertz; };
int main() { static_assert( has_member_cMem_of_type<Dvonn, Gipf>::value, "one"); static_assert(!has_member_cMem_of_type<Dvonn, int>::value, "two");
static_assert(!has_member_cMem_of_type<Tzaar, Gipf>::value, "three"); static_assert( has_member_cMem_of_type<Tzaar, int>::value, "four");
static_assert(!has_member_cMem_of_type<Yinsh, Gipf>::value, "five"); static_assert(!has_member_cMem_of_type<Yinsh, int>::value, "six"); }

Edward Diener <eldiener@tropicsoft.com> writes:
I will continue to look for a workaround for VC9 and earlier, as I think my library should be usable by VC9, VC8, and perhaps VC7.1. Thanks for your neat solution for VC10 !
The following works with VC8, VC10 and g++ 4.4. It causes an Internal Compiler Error with VC7.1 though :-( #include <iostream> typedef char small_type; struct large_type { small_type dummy[2]; }; template<bool,typename T> struct enable_if; template<typename T> struct enable_if<true,T> { typedef T type; }; template<typename T,typename DT> struct has_member_cMem_of_type { template<typename U> static small_type check2(DT (U::*)); template<typename U> static large_type check2(U); template<typename U> static typename enable_if< sizeof(check2(&U::cMem))==sizeof(small_type), small_type>::type has_matching_member(int); template<typename U> static large_type has_matching_member(...); static const bool value=sizeof(has_matching_member<T>(0))==sizeof(small_type); }; struct Gipf { }; struct Dvonn { Gipf cMem; }; struct Tzaar { int cMem; }; struct Yinsh { int Zertz; void cMem(); }; struct Derived: Dvonn {}; int main() { std::cout<<"one:" <<has_member_cMem_of_type<Dvonn, Gipf>::value<<std::endl; std::cout<<"two" ": "<<!has_member_cMem_of_type<Dvonn, int>::value<<std::endl; std::cout<<"three" ": "<<!has_member_cMem_of_type<Tzaar, Gipf>::value<<std::endl; std::cout<<"four" ": "<< has_member_cMem_of_type<Tzaar, int>::value<<std::endl; std::cout<<"five" ": "<<!has_member_cMem_of_type<Yinsh, Gipf>::value<<std::endl; std::cout<<"six" ": "<<!has_member_cMem_of_type<Yinsh, int>::value<<std::endl; std::cout<<"seven" ": "<<has_member_cMem_of_type<Derived, Gipf>::value<<std::endl; std::cout<<"eight" ": "<<!has_member_cMem_of_type<Derived, int>::value<<std::endl; } Anthony -- Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/ just::thread C++0x thread library http://www.stdthread.co.uk Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

On 12/9/2010 5:35 AM, Anthony Williams wrote:
Edward Diener<eldiener@tropicsoft.com> writes:
I will continue to look for a workaround for VC9 and earlier, as I think my library should be usable by VC9, VC8, and perhaps VC7.1. Thanks for your neat solution for VC10 !
The following works with VC8, VC10 and g++ 4.4. It causes an Internal Compiler Error with VC7.1 though :-(
Thanks, Anthony ! Works with VC9 also. I will play around more with VC7.1 but I will not worry if I can not get it to work there as that is a pretty old version of VC now. My original code works with gcc 4+ so gcc is not an issue.
#include<iostream>
typedef char small_type;
struct large_type { small_type dummy[2]; };
template<bool,typename T> struct enable_if;
template<typename T> struct enable_if<true,T> { typedef T type; };
template<typename T,typename DT> struct has_member_cMem_of_type { template<typename U> static small_type check2(DT (U::*)); template<typename U> static large_type check2(U);
template<typename U> static typename enable_if< sizeof(check2(&U::cMem))==sizeof(small_type), small_type>::type has_matching_member(int); template<typename U> static large_type has_matching_member(...);
static const bool value=sizeof(has_matching_member<T>(0))==sizeof(small_type); };
struct Gipf { };
struct Dvonn { Gipf cMem; };
struct Tzaar { int cMem; };
struct Yinsh { int Zertz; void cMem(); };
struct Derived: Dvonn {};
int main() { std::cout<<"one:"<<has_member_cMem_of_type<Dvonn, Gipf>::value<<std::endl;
std::cout<<"two" ":"<<!has_member_cMem_of_type<Dvonn, int>::value<<std::endl;
std::cout<<"three" ":"<<!has_member_cMem_of_type<Tzaar, Gipf>::value<<std::endl; std::cout<<"four" ":"<< has_member_cMem_of_type<Tzaar, int>::value<<std::endl;
std::cout<<"five" ":"<<!has_member_cMem_of_type<Yinsh, Gipf>::value<<std::endl; std::cout<<"six" ":"<<!has_member_cMem_of_type<Yinsh, int>::value<<std::endl;
std::cout<<"seven" ":"<<has_member_cMem_of_type<Derived, Gipf>::value<<std::endl; std::cout<<"eight" ":"<<!has_member_cMem_of_type<Derived, int>::value<<std::endl; }
Anthony

On 12/6/2010 4:38 PM, Edward Diener wrote:
The error report to Microsoft is at https://connect.microsoft.com/VisualStudio/feedback/details/624757/incorrect...
The only thing that bug report says is:
An attempt to choose correctly between two function templates when calling a function fails when one of the function templates takes a pointer to member data and the data has an aggregate type.
In my experience, that's FAR too little information for them to actually use. For instance, this program would seem to satisfy your description, and yet VC10 compiles it just fine. struct S { int i; }; template<class T> void foo( int S::* ) {} template<class T> void foo( T * ) {} int main() { foo( (char*)0 ); } You should always attach a repro to your bug reports. -- Eric Niebler BoostPro Computing http://www.boostpro.com

On 12/6/2010 5:02 PM, Eric Niebler wrote:
On 12/6/2010 4:38 PM, Edward Diener wrote:
The error report to Microsoft is at https://connect.microsoft.com/VisualStudio/feedback/details/624757/incorrect...
The only thing that bug report says is:
An attempt to choose correctly between two function templates when calling a function fails when one of the function templates takes a pointer to member data and the data has an aggregate type.
I agree that is not a full explanation, but then again if you look at the attachment you see the full example.
In my experience, that's FAR too little information for them to actually use. For instance, this program would seem to satisfy your description, and yet VC10 compiles it just fine.
struct S { int i; };
template<class T> void foo( int S::* ) {}
template<class T> void foo( T * ) {}
int main() { foo( (char*)0 ); }
You should always attach a repro to your bug reports.
The attachment in the bug report shows the bug. You probably missed that there is an attachment illustrating the bug.
participants (6)
-
Anthony Williams
-
Dave Abrahams
-
Edward Diener
-
Eric Niebler
-
Jim Bell
-
Stephan T. Lavavej