Opened 10 years ago
Closed 4 years ago
#7251 closed Patches (obsolete)
is_convertible works incorrectly for rvalue source types
Reported by: | Michel Morin | Owned by: | John Maddock |
---|---|---|---|
Milestone: | To Be Determined | Component: | type_traits |
Version: | Boost Development Trunk | Severity: | Problem |
Keywords: | Cc: |
Description
As reported by John Bytheway at
boost-devel ML,
non-intrinsic version of is_convertible<From, To>
works incorrectly when From
is rvalues.
The current code incorrectly handles From
as an lvalue, even if it is an rvalue.
Attachments (1)
Change History (8)
by , 10 years ago
Attachment: | fix_is_convertible_for_rvalues_cxx11.patch added |
---|
comment:2 by , 10 years ago
(In [80234]) Move new test cases into the "tricky" section as many compilers can't handle them. Revert previous change that used std::is_convertible on GCC as it breaks code prior to gcc-4.7. Fix MSVC intrinsic to handle function types better. Filter out rvalue-refs from is_function. Partially apply patch from #7251 to make is_convertible behave more according to C++11. Refs #7251.
comment:3 by , 10 years ago
Michel,
I've moved the extra test cases you added into the tricky*.cpp files as more than a few compilers fail these cases (once the main test file stops building, then we're no longer testing anything at all on that compiler, so I'd prefer to keep troublesome test cases separate).
I've applied the patch, but restricted it's application to GCC to versions 4.7 and later - earlier versions don't build the test suite with the patch applied :-( Versions 4.5.x and 4.6.x fail to build with function types, while version 4.4.x fails with just about everything.
It's possible that an extra #if branch for SFINAE-expressions could fix the remaining issues, but equally it might just break more stuff :-(
Cheers, John.
comment:4 by , 10 years ago
Hi John,
Thanks for looking into the problem.
I've applied the patch, but restricted it's application to GCC to versions 4.7 and later - earlier versions don't build the test suite with the patch applied :-
(Versions 4.5.x and 4.6.x fail to build with function types,
gcc 4.3-4.6 implements C++0x drafts, and there are some inconsistencies with C++11. For example,
- gcc 4.3-4.4: rvalue references can be bound to lvalues.
- gcc 4.5-4.6: rvalue references to function type is not an lvalue. So, for a function type
Func
,Func&
cannot be bound toFunc&&
. Accordingly,is_convertible<Func, Func&>
returns different results than C++11 and this causes the test failures.
while version 4.4.x fails with just about everything.
It's possible that an extra #if branch for SFINAE-expressions could fix the remaining issues, but equally it might just break more stuff :-(
Since T
is not a dependent type in_m_check
, SFINAE is not related. Indeed, the errors on gcc 4.3-4.4 can be reproduced without using templates. (And note that gcc 4.4 supports SFINAE for expressions.) I guess that the reason for the test failures on gcc 4.3-4.4 is a compiler's bug related to rvalue references.
#if
branch is not needed for BOOST_NO_SFINAE_EXPR
, but is needed for __GNUC__ == 4 && (__GNUC_MINOR__ == 3 || __GNUC_MINOR__ == 4)
.
comment:5 by , 10 years ago
On gcc 4.5-4.6 in a C++11 mode, Func&&
cannot be bound to const Func&
.
This is because,
- An rvalue reference to function type is an rvalue, on these compilers.
- Function type cannot be cv-qualified.
So, on these compilers, any_conversion
needs constructors taking rvalue references:
struct any_conversion { #ifndef BOOST_NO_RVALUE_REFERENCES template <typename T> any_conversion(T&&); #else template <typename T> any_conversion(const volatile T&); template <typename T> any_conversion(const T&); template <typename T> any_conversion(volatile T&); template <typename T> any_conversion(T&); #endif };
Or maybe the following is enough:
struct any_conversion { #ifndef BOOST_NO_RVALUE_REFERENCES template <typename T> any_conversion(T&&); #else template <typename T> any_conversion(T&); #endif };
I'm planning to make a patch which enables the recently introduced is_convertible
code on gcc 4.5-4.6 with the above any_conversion
modification. Does it make sense?
comment:6 by , 10 years ago
I have some questions.
First, here is the description of is_convertible
from the C++11 Standard:
Given the following function prototype:
template <class T> typename add_rvalue_reference<T>::type create();the predicate condition for a template specialization
is_convertible<From, To>
shall be satisfied if and only if the following code would be well-formed, including any implicit conversions to the return type of the function:To test() { return create<From>(); }
In C++11, for a function type Func
, is_convertible<Func, Func&>
returns true_type. But, on gcc 4.5-4.6, Func&&
cannot be convertible to Func&
.
My question is "What should is_convertible<Func, Func&>
return on gcc 4.5-4.6?"
Also, in C++03, what should is_convertible<Func, Func*>
return?
It would be reasonable to return true_type, since is_convertible<Func, Func*>
returns true_type in C++11.
But we can make another interpretation. Boost's interpretation of C++03 add_rvalue_reference<T>
is just returning T
. Accordingly, declval<T>()
returns a value of T
. So,
template <class T> typename add_rvalue_reference<T>::type create(); To test() { return create<From>(); }
is ill-formed when From
is a function type. With this interpretation, is_convertible<Func, Func*>
should return false_type.
comment:7 by , 4 years ago
Resolution: | → obsolete |
---|---|
Status: | new → closed |
I believe this to be essentially obsolete now, please file a new issue on Github if not.
Patch for C++11