C ++ 11 std :: is_convertible behavior with private copy constructor

I am trying to understand std::is_convertible in C ++ 11. According to cppreference.com , std::is_convertible<T,U>::value should be evaluated as 1 iff "If an imaginary value of type T can be used in the return statement of a function returning U " The wording says nothing about where this function can be declared. What can you expect when the copy constructor U is private? What can be expected when T is an lvalue reference?

For example, consider this code:

 #include <iostream> #include <type_traits> struct Fact_A; struct A { friend struct Fact_A; A() = default; A(A&&) = delete; private: A(const A&) = default; }; struct Ref_A { A* _ptr; Ref_A(A* ptr) : _ptr(ptr) {} operator A& () { return *_ptr; } }; struct Fact_A { static A* make_A(const A& a) { return new A(a); } static A f(A* a_ptr) { return Ref_A(a_ptr); } //static A g(A&& a) { return std::move(a); } }; int main() { A a1; A* a2_ptr = Fact_A::make_A(a1); (void)a2_ptr; std::cout << std::is_convertible< Ref_A, A >::value << "\n" // => 0 << std::is_convertible< Ref_A, A& >::value << "\n" // => 1 << std::is_convertible< A&, A >::value << "\n"; // => 0 } 

I am using gcc-4.8.2 or clang-3.4 (there is no difference in output) and I am compiling with:

 {g++|clang++} -std=c++11 -Wall -Wextra eg.cpp -o eg 

Here std::is_convertible< Ref_A, A > reports 0 . However, you can see that Fact_A::f returns an object of type A , and an rvalue of type Ref_A used in its return statement. The problem is that copy constructor A is private , so the function cannot be hosted anywhere. Is the current behavior correct according to the standard?

Second question. If I delete private , the output goes to 1 1 1 . What does the last 1 mean? What is an "rvalue of type A& "? Is this a link to rvalue? As you may have noticed, I explicitly deleted the move constructor A As a result, I cannot declare Fact_A::g . But still std::is_convertible< A&, A > reports 1 .

+7
c ++ language-lawyer c ++ 11 std typetraits
source share
1 answer

is_convertible defined in [meta.rel] / 4 of n3485:

Given the following function prototype:

 template <class T> typename add_rvalue_reference<T>::type create(); 

the predicate condition for the type specialization is_convertible<From, To> must be satisfied if and only if the return expression in the following code is well-formed, including any implicit conversions to the return type function:

 To test() { return create<From>(); } 

and here you need to move / copy To : the return statement applies an implicit conversion, this requires the available copy / move constructor if To is a class type ( T& not a class type).

Compare with [conv] / 3

An expression e can be implicitly converted to type T if and only if the declaration T t=e; well formed for some invented time variable T


If From is T& you get something like

 To test() { return create<T&>(); } 

which, like std::declval , is an lvalue: the create<T&>() expression has / gives an lvalue, since T& && (via add_rvalue_reference ) is collapsed to T& .

+6
source share

All Articles