2008-10-06 4 views
41

Ich weiß, dass Sie C++ - Schlüsselwort 'explizit' für Konstruktoren von Klassen verwenden können, um eine automatische Konvertierung von Typ zu verhindern. Können Sie denselben Befehl verwenden, um die Konvertierung von Parametern für eine Klassenmethode zu verhindern?Können Sie das Schlüsselwort explizit verwenden, um die automatische Konvertierung von Methodenparametern zu verhindern?

Ich habe zwei Klassenmitglieder, eine, die eine Bool als ein Param, die andere ein unsigned Int. Als ich die Funktion mit einem int aufgerufen habe, hat der Compiler den Parameter in bool konvertiert und die falsche Methode aufgerufen. Ich weiß, irgendwann werde ich den Bool ersetzen, aber vorerst will ich die anderen Routinen nicht brechen, da diese neue Routine entwickelt wird.

+0

Fragte sich die gleiche Sache und denke, das wäre nützliche Syntax für bestimmte freie Funktionen. Normalerweise möchte ich, dass der Verweis auf eine abgeleitete Klasse implizit die Basisklasse liefert, außer in den Fällen, in denen ein unerwünschtes Slicing auftreten könnte, wie bei einer swap() - Funktion. Tausch (explizite Foo & lhs, explizite Foo & rhs) wäre tröstlich. –

Antwort

51

, können Sie nicht explizit verwenden, aber Sie können dies tun, statt:

class ClassThatOnlyTakesBoolsAndUIntsAsArguments 
{ 
public: 
    void Method(bool arg1); 
    void Method(unsigned int arg1); 

    // Below just an example showing how to do the same thing with more arguments 
    void MethodWithMoreParms(bool arg1, SomeType& arg2); 
    void MethodWithMoreParms(unsigned int arg1, SomeType& arg2); 

private: 
    template<typename T> 
    void Method(T arg1); 

    // Below just an example showing how to do the same thing with more arguments 
    template<typename T> 
    void MethodWithMoreParms(T arg1, SomeType& arg2); 
}; 

Wiederholen Sie dieses Muster für jede Methode, die die bool oder unsigned int nimmt. Stellen Sie keine Implementierung für die templated Version der Methode bereit.

Dadurch wird der Benutzer gezwungen, immer explizit die bool oder unsigned int-Version aufzurufen.

Jeder Versuch Method mit einem anderen Typ als bool oder unsigned int anrufen wird nicht kompilieren, da das Mitglied der Standard Ausnahmen Sichtbarkeitsregeln privat, unterliegt, natürlich (Freund, interne Anrufe, etc.). Wenn etwas, das Zugriff hat, die private Methode aufruft, erhalten Sie einen Linker-Fehler.

+0

Aber das wird alle automatischen Konvertierungen deaktivieren. – Lev

+0

Ja, es werden alle automatischen Konvertierungen deaktiviert. Dan möchte "die Konvertierung von Parametern für eine Klassenmethode verhindern", pro Fragetext, und diese Methode befriedigt das. Es gibt Möglichkeiten, die Vorlagenspezialisierung zu verwenden, so dass wir grundlegende Typen bestimmten Methoden zuordnen können, falls dies gewünscht wird. –

0

Compiler gab "mehrdeutige Anruf" Warnung, die ausreichend sein wird.

Ich war TDD Entwicklung und nicht realisiert, dass ich vergessen habe, den entsprechenden Aufruf in das Mock-Objekt zu implementieren.

+0

Sie sollten in Betracht ziehen, die Frage so zu aktualisieren, dass das angezeigte Problem das Problem war (falsche Methode wurde ausgewählt), war jedoch nicht das Problem. Ich habe das für meine eigenen Zwecke noch einmal angeschaut und festgestellt, dass selbst meine Lösung dies nicht notwendigerweise anspricht, abhängig von den Argumenten. –

-1

Sie könnten auch eine int-Version schreiben, die den bool-Aufruf aufruft.

+1

Er will solches Verhalten verhindern. –

12

Nr. explicit verhindert die automatische Konvertierung zwischen bestimmten Klassen, unabhängig vom Kontext. Und natürlich können Sie das nicht für integrierte Klassen tun.

+0

Abgestimmt; Das beantwortet die Frage doch richtig. –

0

bool IS ein int, das entweder auf 0 oder 1 beschränkt ist. Das ist das ganze Konzept von return 0 ;, es ist logisch das gleiche wie sagen return false; (Verwenden Sie dies jedoch nicht im Code). Kein

+1

Ich glaube, Bool ist ein eigener Typ in C++. –

+0

Ja, es ist ein Typ, aber der Typ kann nur int-Werte von 0 und 1 enthalten. Wenn ich mich an meinen C++ - Lehrer aus meinen Collage-Tagen erinnere, ist 0 falsch und alles andere ist wahr. Dies ist die innere Funktion von Bool, nicht wie es angewendet werden sollte. – WolfmanDragon

+0

Nicht ein Idiot sein, aber "Collage Tage"? Hehehe ... hat mich zum Lachen gebracht. –

2

Etwas, das für Sie arbeiten könnte, ist die Verwendung von Vorlagen. Die folgende Abbildung zeigt, dass die Vorlagenfunktion foo<>() auf bool, unsigned int und int spezialisiert ist. Die Funktion main() zeigt an, wie die Anrufe gelöst werden. Beachten Sie, dass Anrufe, die eine Konstante int verwenden, die kein Typenuffix angeben, in foo<int>() aufgelöst werden. Sie erhalten also einen Fehler beim Aufruf von foo(1), wenn Sie sich nicht auf int spezialisieren. Wenn dies der Fall ist, müssen Anrufer, die eine ganzzahlige Ganzzahlkonstante verwenden, das Suffix "U" verwenden, um den Aufruf zu lösen (dies könnte das gewünschte Verhalten sein).

Ansonsten werden Sie auf int und verwenden Sie die "U" Suffix spezialisieren müssen oder auf ein unsigned int werfen, bevor es auf die unsigned int Version vorbei (oder vielleicht tun einen behaupten, dass der Wert nicht negativ ist, wenn das ist, was Sie wollen).

#include <stdio.h> 

template <typename T> 
void foo(T); 

template <> 
void foo<bool>(bool x) 
{ 
    printf("foo(bool)\n"); 
} 


template <> 
void foo<unsigned int>(unsigned int x) 
{ 
    printf("foo(unsigned int)\n"); 
} 


template <> 
void foo<int>(int x) 
{ 
    printf("foo(int)\n"); 
} 



int main() 
{ 
    foo(true); 
    foo(false); 
    foo(static_cast<unsigned int>(0)); 
    foo(0U); 
    foo(1U); 
    foo(2U); 
    foo(0); 
    foo(1); 
    foo(2); 
} 
+0

Ich dachte darüber nach, es auch so zu machen; mit foo Aufruf foo explizit zuordnen. Dies ist ein besserer Weg, wenn er einige Conversions zulassen möchte, aber nicht alle. –

+0

Eigentlich ist dies die gleiche Methode wie bei Ihnen. Als ich kurz vor der Veröffentlichung Ihre gescannt habe, wurde ich von den Multi-Parameter-Prototypen abgewimmelt und dachte, dass Ihre Technik etwas anderes macht, was ich nicht vollständig verstanden habe. Ich hätte es genauer lesen sollen. –

+0

Ah - die Multi-Parameter-Versionen sollten verdeutlichen, dass es nicht nur für Single-Parm-Methoden gilt, sondern dass nur das fragliche Argument templatisiert werden muss. Vielleicht waren sie verwirrender als vorteilhaft? Ich werde einen Kommentar hinzufügen, um dies zu klären. –

6

Das Folgende ist ein sehr einfacher Wrapper, der eine starke typedef verwendet werden kann, schaffen:

template <typename V, class D> 
class StrongType 
{ 
public: 
    inline explicit StrongType(V const &v) 
    : m_v(v) 
    {} 

    inline operator V() const 
    { 
    return m_v; 
    } 

private: 
    V m_v; // use V as "inner" type 
}; 

class Tag1; 
typedef StrongType<int, Tag1> Tag1Type; 


void b1 (Tag1Type); 

void b2 (int i) 
{ 
    b1 (Tag1Type (i)); 
    b1 (i);    // Error 
} 

Ein nettes Feature dieses Ansatzes ist, dass Sie auch zwischen verschiedenen Parametern mit dem gleichen unterscheiden können Art. Zum Beispiel könnten Sie folgende Voraussetzungen erfüllt sein:

class WidthTag; 
typedef StrongType<int, WidthTag> Width; 
class HeightTag; 
typedef StrongType<int, HeightTag> Height; 

void foo (Width width, Height height); 

Es werden Klienten ‚foo‘ klar sein wird, das Argument ist, welche.

+0

Obwohl die Frage ziemlich alt ist (9 Jahre Gedanke): Jedes Mal, wenn ich 'foo' mit zwei Integer-Parametern aufrufen will, muss ich' foo (Höhe (int_1), Breite (int_2)) 'schreiben, was die explizite Konvertierung findet Operator durch argumentabhängiges Lookup/Koenigs Lookup? – SebNag

+0

@SebTu: Nein. "Höhe" und "Breite" müssen durch Nicht-ADL-Suche gefunden werden. Der Ausdruck 'Height (int_1)' ist eine explizite Typumwandlung, die dazu führt, dass der Konstruktor der 'Height' aufgerufen wird. ADL gilt hier nicht. Um auf "NS :: Height" oder "NS :: Width" zu verweisen, müssen wir entweder eine using directive/declaration verwenden oder die Namen explizit qualifizieren. –

Verwandte Themen