2014-04-11 13 views
7

Próbuję zrozumieć std::is_convertible w C++ 11. Zgodnie z cppreference.com, powinno być ocenione na 1 iff "Jeśli wyimaginowana wartość rinalna typu T może być użyta w instrukcji return funkcji zwracającej U". Sformułowanie to nie mówi nic o tym, gdzie można by zadeklarować tę funkcję. Czego można się spodziewać, gdy konstruktor kopii U jest prywatny? Czego można się spodziewać, gdy T jest odniesieniem do lwartości?C++ 11 std :: is_convertible zachowanie z prywatnym konstruktorem kopii

przykład rozważyć ten kod:

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

Używam gcc-4.8.2 lub clang-3.4 (brak różnicy w wyjściu) i skompilować z:

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

Tutaj std::is_convertible< Ref_A, A > raportów 0. Można jednak zauważyć, że Fact_A::f zwraca obiekt typu A, a wartość rinalna typu Ref_A jest używana w jego instrukcji return. Problem polega na tym, że konstruktorem kopii A jest private, więc tej funkcji nie można umieścić nigdzie indziej. Czy obecne zachowanie jest prawidłowe w odniesieniu do normy?

Drugie pytanie. Jeśli usuniemy private, dane wyjściowe zmienią się w 1 1 1. Co oznacza ostatni 1? Co to jest "wartość rażenia typu A&"? Czy to jest odwołanie do wartości rvalue? Ponieważ możesz zauważyć, że jawnie usunąłem konstruktor ruchu z A. W wyniku tego nie mogę zadeklarować Fact_A::g. Ale nadal, std::is_convertible< A&, A > raportów 1.

Odpowiedz

6

is_convertible jest zdefiniowana w następujący sposób [meta.rel]/4 z n3485:

Biorąc pod uwagę następujący prototyp funkcji:

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

warunek orzeczenie o specjalizacji szablonu is_convertible<From, To> będzie spełnione wtedy i tylko wtedy, gdy wyrażenie zwrotne w poniższym kodzie byłoby dobrze sformułowane, w tym wszelkie niejawne konwersje na typ zwracany dla funkcji:

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

i tu trzeba ruchomy/copyable To: Zwrot-oświadczenie dotyczy niejawna konwersja, a to wymaga dostępnego konstruktora Kopiuj/przenieś jeśli To jest typem klasy (T& nie jest klasa rodzaj).

Porównaj [conv]/3

Wyrażenie e można niejawnie przekształcany typu T wtedy i tylko wtedy, gdy zgłoszenie T t=e; jest sensowne dla niektórych wynalazł tymczasowa zmienna t.


Jeśli From jest T&, masz coś

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

który, podobnie jak std::declval jest lwartością: Wyrażenie create<T&>() jest/daje lwartością, ponieważ T& && (przez add_rvalue_reference) jest zwinięty do T&.

+0

Dzięki za referencję. Oprócz tego, co powiedziałeś, jest więcej tekstu bezpośrednio pod cytowaną wersją szkicu, która wyraźnie wspomina o problemach z kontekstem. Przyjmę to. Przypuszczam, że pozostaje pytanie, czy norma postępuje słusznie. Nie podoba mi się to, że 'is_convertible' wydaje się niepotrzebnie związany z dostępnością konstruktora' To', który nie ma nic wspólnego z 'From' lub relacją między' From' i 'To'. Mogę sobie wyobrazić sytuacje, w których naprawdę chcę wiedzieć, czy konwersja może zostać dokonana w kontekście mojego wyboru ... –

+1

@MateiDavid 'is_convertible' próbuje symulować definicję * niejawnie wymienialnego *, co uważam za nieco nieintuicyjne. Sama definicja wymaga dostępnego konstruktora kopiowania/przenoszenia. Może w twoim kontekście "is_constructible" ma więcej sensu. – dyp

Powiązane problemy