Поведение C++11 std::is_convertible с частным конструктором копирования

StackOverflow https://stackoverflow.com//questions/23003942

Вопрос

Я пытаюсь понять std::is_convertible в С++11.В соответствии с cppreference.com, std::is_convertible<T,U>::value должно оцениваться как 1, если и только если "Если мнимое значение типа T может использоваться в операторе return функции, возвращающей U".Однако в формулировке ничего не говорится о том, где может быть объявлена ​​эта функция.Чего следует ожидать, когда конструктор копирования U является частным?Чего следует ожидать, когда T это ссылка на lvalue?

Например, рассмотрим этот код:

#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.2 или clang-3.4 (никакой разницы в выводе), и я компилирую с помощью:

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

Здесь, std::is_convertible< Ref_A, A > отчеты 0.Однако вы можете видеть это Fact_A::f возвращает объект типа A, и значение типа r Ref_A используется в его операторе возврата.Проблема в том, что конструктор копирования A является private, поэтому эту функцию нельзя разместить где-либо еще.Правильно ли текущее поведение по отношению к стандарту?

Второй вопрос.Если я удалю private, вывод превращается в 1 1 1.Что означает последний 1 иметь в виду?Что такое «rvalue типа A&"?Это ссылка на rvalue?Поскольку вы могли заметить, что я явно удалил конструктор перемещения A.В связи с этим я не могу объявить Fact_A::g.Но все равно, std::is_convertible< A&, A > отчеты 1.

Это было полезно?

Решение

is_convertible определяется следующим образом в [meta.rel]/4 из n3485:

Учитывая следующий прототип функции:

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

условие предиката для специализации шаблона is_convertible<From, To>Должны быть удовлетворены тогда и только тогда, когда выражение возврата в следующем коде будет хорошо сформировано, включая любые неявные преобразования в тип возврата функции:

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

и здесь вам нужен перемещаемый/копируемый To:Оператор return применяет неявное преобразование, и для этого требуется доступный конструктор копирования/перемещения, если To это тип класса (T& не является типом класса).

Сравните с [conv]/3

Выражение e может быть неявно преобразовано к типу T тогда и только тогда, когда объявление T t=e; правильно сформирован для некоторой изобретенной временной переменной t.


Если From является T&, вы получите что-то вроде

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

который, подобно std::declval, является lvalue:Выражение create<T&>() is/дает lvalue, так как T& && (с помощью add_rvalue_reference) свернуто в T&.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top