Я думаю, что лучше всего использовать const char (&s)[N]
(с template<size_t N>
) в качестве типа параметра. Но он также связывается с любым массивом const char, отличным от строкового литерала.
Добавить удаленный конструктор массива без const char, чтобы запретить вызов его с помощью неконстантного массива.
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;
};
Кроме этого, вы можете использовать макро-обертку, который (если конструктор никогда не используется без него) делает возможным только построить объект из буквальных, даже через переменный.
#define MakeLitRf(s) LitRf(s "")
Идея состоит в том, чтобы объединить две строки литералов, из которых вторая одна является просто пустая строка. Это возможно только в том случае, если первый также является строковым литералом; при установке переменной возникает синтаксическая ошибка. После макрорасширения компилятор видит что-то вроде LitRf("foo" "")
, что эквивалентно LitRf("foo")
. Некоторые примеры:
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...
В последнем случае пользователь случайно (? Или намеренно) не использовать макрос, чтобы сделать нашу работу бесполезной. Для того, чтобы сделать это не в состоянии тоже добавить скрытый параметр в конструктор, который необходимо добавить, когда вызывается непосредственно (и в определении макроса, конечно):
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)
Лучшее, что я могу придумать, чтобы обеспечить шаблонную перегрузку, которую статические_ассылки, или использовать явное ключевое слово. – Borgleader
@Borgleader Но я не думаю, что существует способ различать строковый литерал и массив const char. – HolyBlackCat
@Borgleader Как бы вы 'static_assert' что-то было строковым литералом? И как здесь может помочь «явный»? Фактически, если вы можете 'static_assert', что что-то является строковым литералом, вы также можете использовать то же условие с SFINAE для управления разрешением перегрузки, чтобы не привязываться к функции в первую очередь. – 5gon12eder