Domyślam się, że najlepiej jest użyć const char (&s)[N]
(z template<size_t N>
) jako typ parametru. Ale wiąże się również z dowolną tablicą znaków stałych inną niż literał łańcuchowy.
Dodanie konstruktora niewymiennej tablicy char, aby zabronić wywoływania jej za pomocą tablicy niezmiennej.
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;
};
Poza tym, można użyć makro owijkę, która (gdy konstruktor nigdy nie jest używany bez niego) pozwala jedynie na budowę obiektu z dosłownym, nawet za pomocą zmiennej.
Chodzi o połączenie dwóch ciągów literowych, z których drugi to pusty ciąg. Jest to możliwe tylko wtedy, gdy pierwszy jest również literałem ciągu; wstawienie zmiennej powoduje błąd składni. Po rozwinięciu makr kompilator widzi coś w rodzaju LitRf("foo" "")
, co jest równoważne z LitRf("foo")
. Kilka przykładów:
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...
W tym ostatnim przypadku, użytkownik niechcący (? Lub celowo) nie korzystać z makr, dzięki czemu nasza praca bezwartościowe. Aby sprawić, żeby się również zawiedził, dodaj do konstruktora ukryty parametr, który jest wymagany do dodania, gdy zostanie wywołany bezpośrednio (i oczywiście w definicji makra):
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)
Najlepsze co mogę wymyślić to dostarczyć szablonowe przeciążenie, które static_asserts, lub użyj jawnego słowa kluczowego. – Borgleader
@Borgleader Ale nie sądzę, istnieje sposób, aby odróżnić ciąg literal od stałej tablicy char. – HolyBlackCat
@Borgleader W jaki sposób "static_assert" powiedziałbyś, że coś jest literałem ciągu? A w jaki sposób "explicite" może tu pomóc? Właściwie, jeśli możesz 'static_assert', że coś jest literałem ciągu, możesz również użyć tego samego warunku z SFINAE, aby kontrolować rozdzielczość przeciążania, aby nie wiązać się z funkcją w pierwszej kolejności. – 5gon12eder