Переопределить для константных выражений?
Можно ли переопределить функцию и / или шаблон в зависимости от того, является ли что-то постоянным выражением?
По сути, я хотел бы создать строковый класс, который, если передаст статическую строку или переменную constexpr, указывающую на нее, будет просто использовать этот указатель и позже не будет пытаться удалить его.
С другой стороны, если классу передается буфер, ему необходимо либо скопировать его, либо принять его, а затем удалить его в деструкторе.
Я думаю, что наиболее близким является использование сильной typedef и требование от программиста объявлять свои статические строки под этой typedef. Интересно, могут ли те, кто умнее меня, придумать что-то, что не требует этого?
1 ответ
По сути, я хотел бы создать строковый класс, который, если передаст статическую строку или переменную constexpr, указывающую на нее, будет просто использовать этот указатель и позже не будет пытаться удалить его.
Я думаю, что мы столкнулись с проблемой XY здесь. Зная, является ли выражение или нет constexpr
не скажу вам, уместно ли это delete
,
Я бы сказал, что функция не должна пытаться угадать, удалять или нет, если есть вероятность, что это действие неуместно. Я считаю, что вызывающий должен позаботиться об этом, возможно, используя умные указатели, чтобы не заботиться об этом.
Другими словами, я бы позволил функции принять ссылку на lvalue и позволить клиенту разыменовать указатель, если указанный объект должен быть передан в качестве аргумента функции.
Я бы сказал, что эта модель имеет смысл не только в случае delete
: в более общем смысле, если часть кода несет ответственность за решение о том, как некоторые значения должны быть сгенерированы или вычислены (например, распределение объектов), то также ответственность за правильное выполнение некоторых связанных или соответствующих действий (например, очистка) должна принадлежать тому же кусок кода:
void foo(my_object& o)
{
// ...
}
my_object o;
foo(o);
// The argument has automatic storage, no need to delete
my_object* pO = new my_object();
foo(*pO);
// The argument was allocated through operator new, we must
// deallocate it through a corresponding call to delete
delete pO;
Если вы действительно хотите, чтобы очистка происходила в функции, вы должны дать клиенту способ сообщить функции, как ее выполнять:
void foo(my_object& o, bool shouldDelete)
{
// ...
if (shouldDelete) { delete &o; }
}
my_object o;
foo(o, false); // "And don't try to deallocate this object please..."
my_object* pO = new my_object();
foo(*pO, true); // "Please, delete it for me" (we are delegating the
// responsibility of performing the material action,
// but not the one of knowing how!)
Чтобы обеспечить большую гибкость, вы могли бы даже принять вызываемый объект, что еще более проясняет то, что я имел в виду в приведенном выше комментарии, "делегируя ответственность за выполнение материального действия, но не обязанность знать, как":
#include <functional>
void foo(my_object& o, std::function<void()> f = [] () { })
{
// ...
f();
}
int main()
{
my_object o;
foo(o); // "And don't do anything with this object when you're done..."
my_object* pO = new my_object();
foo(*pO, [=] () { delete pO; }); // "Please, do exactly this when done..."
}
Если вам не нужно определять тип вызываемого объекта во время выполнения, вы можете даже рассмотреть возможность поворота foo()
в шаблон функции.
Наконец, что касается вашего первоначального вопроса о том, как определить, является ли выражение постоянным выражением, это вообще невозможно, но есть некоторые приемы, которые могут помочь вам в определенных ситуациях - просто помните об их ограничениях. В связи с этим вы можете найти эти вопросы и ответы в Stackru соответствующими.