Puoi utilizzare la parola chiave esplicita per impedire la conversione automatica dei parametri del metodo?

StackOverflow https://stackoverflow.com/questions/175689

Domanda

So che puoi usare la parola chiave C ++ 'esplicita' per i costruttori di classi per impedire una conversione automatica del tipo. Puoi usare questo stesso comando per impedire la conversione dei parametri per un metodo di classe?

Ho due membri della classe, uno che prende un bool come parametro, l'altro un int senza segno. Quando ho chiamato la funzione con un int, il compilatore ha convertito il parametro in bool e ha chiamato il metodo sbagliato. So che alla fine sostituirò il bool, ma per ora non voglio rompere le altre routine mentre questa nuova routine viene sviluppata.

È stato utile?

Soluzione

No, non puoi usare esplicito, ma puoi farlo invece:

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);
};

Ripeti questo schema per ogni metodo che accetta bool o unsigned int. Non fornire un'implementazione per la versione templatizzata del metodo.

Questo costringerà l'utente a chiamare sempre esplicitamente la versione bool o unsigned int.

Qualsiasi tentativo di chiamare Method con un tipo diverso da <=> o <=> non verrà compilato perché il membro è privato, soggetto alle eccezioni standard alle regole di visibilità, ovviamente (amico, chiamate interne, ecc. .). Se qualcosa che ha accesso chiama il metodo privato, otterrai un errore del linker.

Altri suggerimenti

No. explicit impedisce la conversione automatica tra classi specifiche, indipendentemente dal contesto. E ovviamente non puoi farlo per le classi integrate.

Quello che segue è un wrapper molto semplice che può essere usato per creare un typedef forte:

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
}

Una bella caratteristica di questo approccio è che puoi anche distinguere tra diversi parametri con lo stesso tipo. Ad esempio potresti avere quanto segue:

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

void foo (Width width, Height height);

Sarà chiaro ai clienti di 'pippo' quale argomento è quale.

Qualcosa che potrebbe funzionare per te è usare i template. Di seguito è illustrata la funzione modello foo<>() specializzata in bool, unsigned int e int. La funzione main() mostra come vengono risolte le chiamate. Tieni presente che le chiamate che utilizzano una costante foo<int>() che non specifica un suffisso di tipo si risolveranno in foo( 1), quindi riceverai un errore durante la chiamata "U" se non sei specializzato su <=>. In tal caso, i chiamanti che utilizzano una costante intera letterale dovranno utilizzare il suffisso <=> per risolvere la chiamata (potrebbe trattarsi del comportamento desiderato).

Altrimenti dovrai specializzarti su <=> e usare il <=> suffisso o lanciarlo su un <=> prima di passare alla versione <=> (o forse fare un'asserzione che il valore non è ' t negativo, se è quello che vuoi).

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

Il compilatore ha dato " chiamata ambigua " avvertimento, che sarà sufficiente.

Stavo sviluppando TDD e non mi ero reso conto di aver dimenticato di implementare la chiamata corrispondente nell'oggetto finto.

bool È un int che è limitato a 0 o 1. Questo è l'intero concetto di return 0; è logicamente lo stesso che dire return false; (non usare questo nel codice però).

Potresti anche scrivere una versione int che chiama quella bool.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top