www.digitalmars.com         C & C++   DMDScript  

c++ - [Bug report] Bugs affecting boost::is_convertible

reply Daniel James <daniel calamity.org.uk> writes:
Hi,

I've been trying to get boost::is_convertible to work, and my version
almost always does. But there are a few problems.

The first one is a bit odd. In the following test case, if the commented
out line is uncommented the program fails on the second function call. I
believe that the compiler is reusing the instantiated template
test<int[2]> when it instantiates test<const int[2]> which gives
test<const int[2]>::func a non-const argument type. This causes a lot of
the unit tests for the boost type_traits to fail.

     template<class T>
     struct test
     {
         static void func(T x) {}
     };

     int main()
     {
         int x[2] = {1, 2};
         //test<int[2]>::func(x);

         const int x2[2] = {1, 2};
         test<const int[2]>::func(x2);
     }

Secondly, void* shouldn't be implicitly convertible to other pointer
types, and non-const references shouldn't be initialised from
temporaries (the compiler warns about that, but it should be an error).
Here are the test cases:

     int main() {
         int x;
         char& x2 = x; // This should fail, there is currently a warning
     }

and:

     int main() {
         void* y;
         int* y2 = y; // This should fail
     }

Finally, in the following example the compiler gives a link error
because it can't find test::from, but as from is only referred to from
the 'sizeof' it shouldn't be linked to. (In boost::is_convertible this
is actually in a template, such that 'from' won't have a default
constructor, which is why an instance of it can't be defined). I've
actually got a work around for this one, but it's a little nasty, so it
would be nice if this was fixed.

     struct test { static char from; };

     int check(int const&);
     const int value = sizeof(check(test::from));

     int main(){ }

thanks,

Daniel
Aug 15 2004
parent reply "Walter" <newshound digitalmars.com> writes:
"Daniel James" <daniel calamity.org.uk> wrote in message
news:411FC75F.9050804 calamity.org.uk...
 The first one is a bit odd. In the following test case, if the commented
 out line is uncommented the program fails on the second function call. I
 believe that the compiler is reusing the instantiated template
 test<int[2]> when it instantiates test<const int[2]> which gives
 test<const int[2]>::func a non-const argument type. This causes a lot of
 the unit tests for the boost type_traits to fail.

      template<class T>
      struct test
      {
          static void func(T x) {}
      };

      int main()
      {
          int x[2] = {1, 2};
          //test<int[2]>::func(x);

          const int x2[2] = {1, 2};
          test<const int[2]>::func(x2);
      }

I've had a lot of trouble with const, as sometimes it means a different type and sometimes it doesn't. Are you sure it really means a different template should be instantiated here?
Aug 15 2004
next sibling parent Daniel James <daniel calamity.org.uk> writes:
Walter wrote:
 I've had a lot of trouble with const, as sometimes it means a different type
 and sometimes it doesn't. Are you sure it really means a different template
 should be instantiated here?

Well, I'm not 100% sure, I'm not a languague lawyer. The fact that the first instantiation breaks the second seems to suggest that it should, and the other compilers I've tried have no problems with this. Having said that, it's not a big problem. As far as type_traits are concerned, it may cause some of the tests to fail, but it's unlikely to cause a problem in normal use. I'm sure you've got a lot of far more important things to worry about. thanks, Daniel
Aug 16 2004
prev sibling parent Daniel James <daniel calamity.org.uk> writes:
It looks like there's the same problem with const void. Personally, I'm 
surprised that you can have a const void. Here's a simple test:

     template <class T> struct add_pointer { typedef T* type; };

     int main()
     {
         void* x;
         add_pointer<void>::type x1 = x;

         const void* y;
         add_pointer<const void>::type y1 = y;
     }

Here's a longer, but more realistic, test:

     template <typename T> struct is_const_impl {};

     template <typename T>
     struct is_const_impl<T*> {
         static const bool value = false;
     };

     template <typename T>
     struct is_const_impl<const T*> {
         static const bool value = true;
     };

     template <typename T>
     struct is_const {
         static const bool value = is_const_impl<T*>::value;
     };

     #define STATIC_ASSERT(name, x) \
         typedef char name[(x) ? 1 : -1];

     STATIC_ASSERT(test_const_void, is_const<const void>::value);
     STATIC_ASSERT(test_void, !is_const<void>::value);

     STATIC_ASSERT(test_const_array, is_const<const int[2]>::value);
     STATIC_ASSERT(test_array, !is_const<int[2]>::value);

Volatile acts in a similar manner. But, as I said before, this is 
unlikely to cause problems in normal use.

Daniel
Aug 16 2004