2015-12-31 16 views
7

Przejrzałem wiele pytań związanych z konwersją, ale wydawało się, że żaden z nich nie mówi w ten sposób o jawnym słowie kluczowym. Oto kod:(dotyczy jawnie) Pierwszeństwo z konwersją operatora i konstruktora

struct B; 
struct A{ 
    /*explicit*/ A(const B&){ cout << 1; } // *1 
}; 
struct B{ 
    /*explicit*/ operator A()const{ cout << 2; } // *2 
}; 

void foo(const A &){} 

int main(void){ 
    B b; 
    foo(/*static_cast<A>*/ (b)); // *3 
} 

Wynik: (T: Odkomentowano, N: komentuje X: czy)

# | *1 | *2 | *3 |output| 
1 | N | N | N |error | 
2 | N | N | Y | 1 | 
3 | N | Y | N | 1 | 
4 | N | Y | Y | 1 | 
5 | Y | N | N | 2 | 
6 | Y | N | Y | 1 | 
7 | Y | Y | N |error | 
8 | Y | Y | Y | 1 | 

1, 7 są błędy, co jest normalne (wieloznaczne i bez automatycznej konwersji.)
2 wydaje się, że konstruktor ma wyższy priorytet, ale dlaczego?
3, 5 są łatwe do zrozumienia.
4 jest dziwne, ponieważ nie nazywa tego wyraźnego. czemu?
6 może być spowodowane "jawnym" lub konstruktorem mającym wyższy priorytet. Który jest powodem? 8 wydaje się, że konstruktor ma wyższy priorytet, ale dlaczego?

Czy ktoś mógłby podać jakieś wyjaśnienia? Dzięki!

+0

Jest to jeden z powodów, dla których nie należy mieć konstruktora konwertującego i operatora konwersji - prawie nigdy nie można tego naprawić.A kiedy to robisz, bardzo niewielu ludzi rozumie, dlaczego. –

+0

@ BoPersson, wiem o tym. Po prostu ciekawi mnie, dlaczego kompilator działa w ten sposób. Wiem, że to nie jest praktyczne pytanie. Dzięki – Asu

Odpowiedz

2

Bardzo dobre pytanie.

Przede wszystkim rzecz explicit nie oznacza, że ​​"ma to pierwszeństwo, jeśli wymagana jest jawna konwersja". Oznacza to, że "ta rzecz może zostać wywołana tylko jawnie". Stwarza więc sytuacje, w których nie można się na niego powołać, a nie wymusza ich użycia w innych sytuacjach.

Kolejną rzeczą, którą należy wziąć pod uwagę, jest to, że static_cast to direct initialization, podczas gdy przekazywanie argumentu do funkcji to copy initialization. Między innymi inicjowanie kopiowania nigdy nie używa jawnych konstruktorów. Inną rzeczą, na którą należy zwrócić uwagę, jest to, że bezpośrednia inicjalizacja wymaga użycia konstruktorów dla klas (jawnych lub nie). Chociaż nie oznacza to, że konwersja nie może wykonywać bezpośredniej inicjalizacji: może być użyta do przekonwertowania argumentu konstruktora, a jeśli konstruktor jest kopią generowaną przez kompilator, wówczas będzie on wyglądał tak jak wykonywana funkcja konwersji. bezpośrednia inicjalizacja (podczas gdy w rzeczywistości została wykonana przez konstruktora kopii). Spróbuj zadeklarować konstruktor kopii bez definiowania go (technika wyłączania kopiowania), a zobaczysz, że funkcja konwersji nie działa już w bezpośrednim kontekście inicjalizacji: zostanie skompilowana, ale spowoduje błąd łączenia.

Mając to na uwadze:

  1. oczywiste.
  2. Bezpośrednia inicjalizacja wymaga konstruktora, więc jest wywoływana.
  3. Oczywiste.
  4. Tak samo jak 2, naprawdę. Deklaracja funkcji konwersji explicit zapobiega jedynie niejawnemu wywoływaniu, nie wymusza jej użycia w jawnych kontekstach.
  5. Oczywiste.
  6. Ponownie, bezpośrednia inicjalizacja wymaga konstruktora i pozwala na użycie jawnych.
  7. Oczywiste.
  8. Inna bezpośrednia inicjalizacja.
+0

zmieniłem funkcję foo na void foo (A) {} i dodaj A (const A &) = delete; w strukturze A. Wykonaj ją w przypadku nr 5 i tak, teraz jest to błąd. Dzięki! – Asu

+0

Co więcej, wydaje się, że tak zwany "precedens" jest w rzeczywistości procesem przeciążania. Konstruktor konwersji jest dokładnie dopasowany, podczas gdy konwersja operatora jest w rzeczywistości przy użyciu konstruktora kopii z konwersją parametrów, która nie jest dokładnym dopasowaniem. Mam nadzieję, że nie zrozumiałem tego źle. – Asu

+0

@Asu, mówiąc dokładniej, nazywa się to przeciążeniem _resolution_, ale tak, to jest ogólny pomysł. I nie sądzę, że musisz zmienić sygnaturę 'foo'. Odsyłacz lub nie, ponieważ typ rzeczywistego parametru jest inny niż typ parametru formalnego, kompilator musi mimo to utworzyć kopię, aby przekazać ją sobie lub odwołać się do niej. –

Powiązane problemy