2014-10-16 21 views
8

Dlaczego C++ rzuca literał łańcuchowy, który przechodzę jako bool, a nie ciąg?Przeciążenie Bool/String Niejednoznaczność

#include <iostream> 

using namespace std; 

class A 
{ 
    public: 
     A(string v) 
     { 
      cout << v; 
     } 

     A(bool v) 
     { 
      cout << v; 
     } 
}; 

int main() 
{ 
    A("hello"); 
    return 0; 
} 

wyjściowa: 1

Czy dlatego, że kompilator nie jest wystarczająco inteligentny, aby skakać z char * na łańcuch a raczej po prostu zakłada, że ​​bool jest najbliższa rzecz do wskaźnika? Czy jest moją jedyną opcją tworzenia konstruktora char *, który zasadniczo wykonuje dokładnie to samo, co konstruktor łańcuchów?

+1

Generalnie preferuję jawne konwersje. Konwersje niejawne mają takie funkcje. Zobacz http://stackoverflow.com/q/2346083/10077 –

+0

Nie jestem pewien, ale: możliwe są obie konwersje (konwertowanie wskaźnika na sprawdzanie bool dla wskaźnika pustego). Ale konwersja do bool jest * wbudowaną * konwersją, podczas gdy string jest * zdefiniowaną przez użytkownika * convesion (przez niejawny c'tor). A teraz, jeśli dobrze pamiętam, wbudowane mają wyższy priorytet niż te zdefiniowane przez użytkownika. – leemes

+1

możliwy duplikat [Przeciążenie metody C++ nie działa] (http://stackoverflow.com/questions/14770252/c-method-overload-not-working) –

Odpowiedz

12

Jeśli masz C++ 11 można użyć przekazał mu uprawnienia konstruktora:

A(char const* s) : A(std::string(s)) { } 

Powodem logiczna konwertazy konstruktor dobiera się nad jednym dla std::string dlatego, że konwersja z char const* do bool jest standardową konwersją, podczas gdy jedna na std::string jest konwersją zdefiniowaną przez użytkownika. Standardowe konwersje mają wyższą rangę niż konwersje zdefiniowane przez użytkownika.

3

Z

A(string("hello")); 

da oczekiwanego rezultatu.

Dlaczego tak jest?

Dlatego, standardowe konwersji:

  • "Witam" jest rozumiane jako const char* wskaźnik
  • to wskaźnik może zostać przekształcony w bool (rozdział 4.12 normy: „A prvalue z (...) typ wskaźnika (...) można przekonwertować na wartość typu bool. ")
  • Konwersja z" cześć "na string nie jest brana pod uwagę, ponieważ sekcja 12.3 normy wyjaśnia, że" Konwersje typów obiektów klas mogą być określone przez konstruktorów i przez funkcje konwersji. Konwersje te nazywane są zdefiniowane przez użytkownika konwersje „i” Konwersje zdefiniowane przez użytkownika są stosowane tylko wtedy, gdy są one jednoznaczne”. Czy nie ma konstruktora bool konwersja std::string byłoby zrobić implicitely.

Jak uzyskać to, czego oczekiwano

Wystarczy dodać brakujące konstruktora dla litterals smyczkowych:

A(const char* v) 
{ 
    cout << v; // or convert v to string if you want to store it in a string member 
} 

Oczywiście, zamiast przepisywania konstruktora od nowa, można wybrać delegata zgodnie z sugestią 0x499602D2 w innej odpowiedzi.

+0

Tak, ale nie chcę wypisać 'string (. ..) 'za każdym razem. Czy moja jedyna opcja umożliwia utworzenie konstruktora, który przyjmuje argument "char const *" jako argument? – RPGillespie

+0

Tak! Skończyłem z dodatkowymi wyjaśnieniami. – Christophe

2

Przy wyborze przeciążone metody jest to rozkaz, że kompilator stara:

  1. Dokładne dopasowanie
  2. Promocja
  3. standardowa konwersja numeryczna
  4. zdefiniowane przez użytkownika operatorzy

wskaźnik nie jest promowane pod numerem bool, ale przekształca się w bool. A char* używa operatora std do konwersji na std::string. Zauważ, że jeśli char* użyłby tego samego numeru na tej liście, aby przekonwertować na zarównobool, jak i std::string, nie byłoby jednoznaczne, którą metodę wybrać kompilator, aby kompilator wygenerował błąd "niejednoznacznego przeciążenia".

Podałbym swoją wagę za rozwiązanie 0x499602D2. Jeśli masz C++ 11, najlepiej zadzwoń: A(char* s) : A(std::string(s)){} Jeśli nie masz C++ 11, to utworzę konstruktor A(char* s) i streszczę logikę konstruktora A(std::string) w metodzie i wywołam tę metodę z obu konstruktorzy.

http://www.learncpp.com/cpp-tutorial/76-function-overloading/

2

Ostatnio zdałem ten problem zbyt, pozwól mi podzielić w inny sposób.

Możesz zmienić konstruktor bool na unsigned char. Tak więc nie ma miejsca rozpad i implicit konwersja literału ciągłego, a konstruktor std::string ma miejsce.

class A 
{ 
public: 
    A(string v) 
    { 
     cout << v; 
    } 

    A(unsigned char v) 
    { 
     cout << static_cast<bool>(v); 
    } 
}; 

int main() 
{ 
    A("Hello"); // <- Call A(string) 
    A(false); // <- Call A(unsigned char) 
} 

W ten sposób nie trzeba, aby zapewnić zawsze przeciąża do std::string i const char* ani tworzenia kodu uwędzić konstruowania std::string w miejscu połączenia klient.

Nie twierdzę, że to jest lepsze, ale jest prostsze.

+0

Miałem ten sam problem, ale zastanawiam się, dlaczego A ("Hello"); nie daje ostrzeżenia, ale const char * b = "Hello"; A (b); daje ostrzeżenie 4800: wymuszenie wartości bool "prawda" lub "fałsz"? –

+0

To również zadziałało dla mnie i jest również bardzo przydatne z nowym 'string_view's. Zobacz [tutaj] (https://godbolt.org/g/1uCwR2) na przykład. – Claudius