带有私有复制构造函数的C++11 std::is_convertable行为

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

本文关键字:is convertable 行为 std C++11 复制 构造函数      更新时间:2023-10-16

我正在努力理解C++11中的std::is_convertible。根据cppreference.com,std::is_convertible<T,U>::value的求值应为1,当"如果在返回U的函数的返回语句中可以使用T类型的虚值"时。不过,该措辞没有说明该功能可能在哪里声明。当U的复制构造函数是私有的时,应该期待什么?当T是左值引用时,应该期待什么?

例如,考虑这个代码:

#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
}

我使用gcc-4.8.2clang-3.4(输出没有差异),并使用进行编译

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

这里,std::is_convertible< Ref_A, A >报告0。但是,您可以看到Fact_A::f返回一个类型为A的对象,并且在其返回语句中使用了一个类型Ref_A的右值。问题是A的复制构造函数是private,所以函数不能放在其他地方。目前的行为是否符合标准?

第二项质询。如果我去掉private,输出将变为1 1 1。最后一个1是什么意思?什么是"A&类型的右值"?这是右值参考吗?因为您可能注意到我明确删除了A的move构造函数。因此,我无法声明Fact_A::g。但是,std::is_convertible< A&, A >仍然报告1

is_convertible在n3485:的[meta.rel]/4中定义如下

给定以下功能原型:

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

模板专门化CCD_ 25的谓词条件当且仅当以下代码中的返回表达式格式良好,包括对的返回类型的任何隐式转换功能:

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

这里,您需要一个可移动/可复制的To:return语句应用隐式转换,如果To是类类型(T&不是类类型),则这需要一个可以访问的复制/移动构造函数。

与[conv]/3 比较

对于某些发明的临时变量t,表达式e可以隐式转换为类型T,如果且仅当声明T t=e;是良好形式的。


如果FromT&,你会得到类似的东西

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

类似于std::declval,它是左值:表达式create<T&>()是/产生左值,因为T& &&(通过add_rvalue_reference)被折叠为T&