Действительно ли возможно создать конструктора (или функциональная подпись, в этом отношении), который только принимает строковый литерал, но не, например. char const *
?
Действительно ли возможно иметь две перегрузки, которые могут различать строковые литералы и char const *
?
C++ 0x отчасти позволил бы это с пользовательским суффиксом - но я ищу "более раннее" решение.
Объяснение: предотвращение помещает копию в "кучу" строк, которые не будут изменены при предоставлении как строковые литералы.
Эти строки непосредственно переходят к API, ожидая a const char *
без любой обработки. Большинство вызовов действительно использует литералы, требующие никакой дополнительной обработки, только в нескольких случаях, они создаются. Я ищу возможность сохранить собственное поведение вызова.
Примечание: - так как это подходит в ответах: рассматриваемый код не использует std::string
вообще, но хороший пример был бы:
class foo
{
std::string m_str;
char const * m_cstr;
public:
foo(<string literal> s) : m_cstr(p) {}
foo(char const * s) : m_str(s) { m_cstr = s.c_str(); }
foo(std::string const & s) : m_str(s) { m_cstr = s.c_str(); }
operator char const *() const { return m_cstr; }
}
Результаты:
(1) это не может быть сделано.
(2) Я понял, что даже не ищу литерал, но для постоянного во времени компиляцией (т.е. "что-либо, что не должно быть скопировано").
Я буду, вероятно, использовать следующий шаблон вместо этого:
const literal str_Ophelia = "Ophelia";
void Foo()
{
Hamlet(str_Ophelia, ...); // can receive literal or string or const char *
}
с простым
struct literal
{
char const * data;
literal(char const * p) : data(p) {}
operator const char *() const { return data; }
};
Это не мешает никому злоупотребить им (я должен найти лучшее имя...), но это позволяет необходимую оптимизацию, но остается безопасным по умолчанию.
Нет, вы просто не можете сделать это - строковые литералы и Const Char * являются взаимозаменяемыми. Один обходной путь может заключаться в том, чтобы представить специальный класс для проведения указателей на строковые литералы и сделать конструктор только принять это. Таким образом, когда вам нужно пройти буквальный, вы называете конструктором этого класса и передайте временный объект. Это не полностью предотвращает неправильное использование, но делает код гораздо более ремонтом.
Если вы точно знаете, как вы точно знаете, как ваш компилятор и платформа справится со строчными литералами, можно было бы написать решение Это может сделать это. Если вы знаете, что ваш компилятор всегда ставит строковые литералы в определенную область памяти, вы можете проверить указатель на границах этой памяти. Если он падает в этот блок, у вас есть строковый литерал; В противном случае у вас есть строка, хранящаяся на куче или стеке.
Тем не менее, это решение будет платформенным / компилятором. Это не было бы портативным.
Рабочий раствор на основе IDEA IDEAU :
struct char_wrapper
{
char_wrapper(const char* val) : val(val) {};
const char* val;
};
class MyClass {
public:
template< std::size_t N >
explicit MyClass(const char (&str)[N])
{
cout << "LITERAL" << endl;
}
template< std::size_t N >
explicit MyClass(char (&str)[N])
{
cout << "pointer" << endl;
}
MyClass(char_wrapper m)
{
cout << "pointer" << endl;
}
};
int main()
{
MyClass z("TEST1"); // LITERAL
const char* b = "fff";
MyClass a(b); // pointer
char tmp[256];
strcpy(tmp, "hello");
MyClass c(tmp); // pointer
}
На некоторых платформах мне приходилось объявлять строковые литералы как статический const char *
, чтобы программа имела доступ к тексту из Read-Only Memory. При объявлении как const char *
, ассемблерный листинг показывал, что текст скопирован из ПЗУ в стековую переменную.
Вместо того, чтобы беспокоиться о приемнике, возможно, попробуйте объявить строковые литералы со статическим const char *
.