Basically, what I would like to do is build a string class, which, if you pass a static string or a constexpr variable pointing to one, will simply use this pointer and will not try to delete it later.
I think we are facing the XY-problem here. Knowing whether an expression is constexpr or not will not tell you if it is suitable for delete .
I would say that a function should not try to guess whether to delete or not, if there is a possibility that this action is inappropriate. I believe that the caller should take care of this, perhaps using smart pointers so as not to take care of it.
In other words, I would let the function accept the lvalue reference and allow the client to dereference the pointer if the specified object should be passed as an argument to the function.
I would say that this template makes sense not only in the case of delete : more generally, if a piece of code has a responsibility to decide how some values should be generated or calculated (for example, highlighting an object), then it is also the responsibility to correctly execute some related or appropriate actions (for example, cleaning) should belong to the same code fragment:
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;
If you really want the cleanup to be done in a function, you should give the client a way to tell the function how to do it:
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!)
To provide more flexibility, you can even accept the called object, which is even more clear what I meant in the comment above, "delegating responsibility for performing a material action, but not for 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..." }
If you do not need to determine the type of the called object at runtime, you might even consider turning foo() into a function template.
Finally, regarding your initial question on how to determine if an expression is a constant expression , this is not possible at all, but there are some methods that can help you in cetain situations - just by understanding their limitations. In this regard, you can find fooobar.com/questions/150781 / ....