Thread overview
[Bug report] Bugs affecting boost::is_convertible
Aug 15, 2004
Daniel James
Aug 16, 2004
Walter
Aug 16, 2004
Daniel James
Aug 16, 2004
Daniel James
August 15, 2004
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
August 16, 2004
"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?


August 16, 2004
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
August 16, 2004
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