Immagino che il meglio che puoi fare è usare const char (&s)[N]
(con template<size_t N>
) come tipo di parametro. Ma si lega anche a qualsiasi array di caratteri const diverso da un letterale stringa.
Aggiungere un costruttore di array di char non-const cancellato per proibire di chiamarlo con un array non-const.
class LitRf
{
const char* data_;
Sz size_;
public:
template<size_t N>
LitRf(char const (&s)[N])
: data_{s}, size_{N}
{}
template<size_t N>
LitRf(char (&s)[N]) = delete;
};
Oltre a questo, è possibile utilizzare un involucro macro, che (quando il costruttore non viene mai utilizzata senza) rende possibile solo per costruire un oggetto da un letterale, nemmeno tramite una variabile.
#define MakeLitRf(s) LitRf(s "")
L'idea è di concatenare due stringhe letterali, di cui la seconda è solo una stringa vuota. Questo è possibile solo se il primo è anche un letterale stringa; inserendo una variabile, c'è un errore di sintassi. Dopo l'espansione della macro, il compilatore vede qualcosa come LitRf("foo" "")
che equivale a LitRf("foo")
. Alcuni esempi:
auto x = MakeLitRf("foo"); // works
const char *foo = "foo";
auto x = MakeLitRf(foo); // fails
auto x = LitRf(foo); // works, but we want it to fail...
In quest'ultimo caso, l'utente involontariamente (? O intenzionalmente) non ha utilizzato la macro, rendendo il nostro lavoro inutile. Per farla fallire troppo, aggiungere un parametro nascosto al costruttore, che è richiesto da aggiungere quando viene chiamato direttamente (e nella definizione della macro, ovviamente):
class LitRf
{
const char* data_;
Sz size_;
public:
// Called by the macro MakeLitRf. Unlikely to be called directly unless the user knows what he's doing.
LitRf(const char *s, void *)
: data_{s}, size_{N}
{}
// Called without macro! Throw a compiler error, explaining what's wrong.
LitRf(const char *s)
{
static_assert(false, "Please use the macro `MakeLitRf` with a string literal to construct a `LitRf`.");
}
};
#define MakeLitRf(s) LitRf(s "", nullptr)
Il meglio che posso venire in mente è quello di fornire un sovraccarico basato su modelli che static_assert o utilizza la parola chiave esplicita. – Borgleader
@Borgleader Ma non penso che ci sia un modo per distinguere tra un letterale stringa e un array const-char. – HolyBlackCat
@Borgleader Come vorresti 'static_assert' che qualcosa sia una stringa letterale? E come potrebbe l'aiuto esplicito qui? In realtà, se puoi 'static_assert' che qualcosa è una stringa letterale, puoi usare la stessa condizione anche con SFINAE per controllare la risoluzione di sovraccarico e non legarti alla funzione in primo luogo. – 5gon12eder