2014-09-23 12 views
30

Poniższy kod jest kompilowany z powodu niejawnej konwersji dla char. Nie jestem pewien dlaczego, ponieważ jedyna niejawna konwersja, jakiej oczekiwałbym (i spodziewam się nie udać) jest od char const* do size_t.C++ nieoczekiwana implikowana konwersja

#include <cstddef> 

struct foo 
{ 
    int operator[](size_t i) const { return 1; } 
    operator char() const { return 'a'; } 
}; 

int main() 
{ 
    foo f; 
    f["hello"]; // compilation error desired here 
} 

Co to jest tutaj niejawna konwersja, która pozwala na kompilację? Jeśli usuniemy operator char lub zrobię to explicit, wówczas kompilacja zakończy się niepowodzeniem w żądanym miejscu.

Klasa, z której ten kod jest pobierany naprawdę, wymaga zarówno niejawnej konwersji, jak i operator[]. Czy istnieje sposób, w jaki mogę zapobiec zachowaniu bez wyraźnej konwersji?

+1

Czy próbowałeś dodanie prywatny 'operator [] (char const *)'? –

Odpowiedz

34

Powodem kompilacji wierszy jest to, że z niejawną konwersją można ją ponownie zinterpretować jako 'a'["hello"];, która z kolei jest taka sama, jak pisanie *(('a')+("hello"));, która również kompiluje.

Fragment dla standardu:

5.2.1 indeksowanie:

na ... ekspresji E1, [E2] jest identyczne (z definicji) na * ((E1) + (E2)) ...

Najprostszym obejść bez dokonywania operator konwersji wyraźny jest zadeklarować operatora wykraczająca indeksie jako usunięte:

struct foo 
{ 
    operator char() const { return 'a'; } 
    int operator[](size_t i) const { return 1; } 

    // prevent accidental use of foo["hello"] 
    int operator[](char const*) const = delete; 
}; 
+3

... i przez przemienność, która jest równoważna '* (E2 + E1)' i 'E2 [E1]'? Nie nazwałbym tego oczywistym ... –

+7

@UlrichEckhardt, tak, '" cześć "[0]' jest równoważne '0 [" cześć "]'. – imreal

+4

Rzeczywiście, nie jest to oczywiste. To jest C++. Istnieją książki pełne pułapek i pułapek C++. – Jerry101

0
f["hello"]; 

tłumaczy się na f.operator [] (indeks), gdzie indeksem jest wartość wskaźnika wskazującego "cześć". W twoim przypadku dzwoni do operatora [] (size_t i). W związku z tym jest absolutnie OK, że kompilator nie narzeka. W rzeczywistości wartość indeksu będzie al; wartość Arge (wartość wskaźnika), więc lepiej być ostrożnym przy przeciążeniu [] i sprawdzić, górnej granicy nie W rzeczywistości, jeśli masz:

char *c = "hello"; // c is a pointer 
f[c]; // ok 
+0

Ummm, jest to całkowicie błędne i mylące: 'char *' nie jest niejawnie wymienialne na 'size_t', więc' foo :: operator [] 'nigdy nie jest zaznaczone. 'jest konwertowane na' char', tak aby było tłumaczone na ''a' [" hello "]', które jest takie samo jak '" hello "['a']', które w ascii oznacza '" cześć "[97]' Proszę spojrzeć na odpowiedź, która została przyjęta przed wysłaniem. – marack