Переопределить для константных выражений?

Можно ли переопределить функцию и / или шаблон в зависимости от того, является ли что-то постоянным выражением?

По сути, я хотел бы создать строковый класс, который, если передаст статическую строку или переменную 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 соответствующими.

Другие вопросы по тегам