【问题标题】:Override for constant expressions?重写常量表达式?
【发布时间】:2013-03-14 18:03:49
【问题描述】:

是否可以根据某事物是否为常量表达式来覆盖函数和/或模板?

基本上我想做的是构建一个字符串类,如果传递一个静态字符串或指向一个的 constexpr 变量,它将简单地使用该指针,以后不会尝试删除它。

另一方面,如果给类一个缓冲区,它需要复制或采用它,然后在析构函数中删除它。

我认为最接近的可能是使用强 typedef 并要求程序员在该 typedef 下声明他/她的静态字符串。我想知道那些比我聪明的人是否能想出一些不需要的东西。

【问题讨论】:

  • 根据您的解释,我不明白为什么您应该将文件范围数组与块范围数组区别对待。前者是地址常量表达式,后者不是,但都不应该删除。
  • 你的意思是重载而不是覆盖,对吧?
  • 不幸的是,如果不让用户告诉你,没有办法查明传递的参数是否最初是一个常量表达式。
  • @Xeo - 如果你提出来,我认为这是一个可行的答案。
  • 字符串是有问题的,特别是因为字符串文字总是左值。

标签: c++ templates c++11 overloading constexpr


【解决方案1】:

基本上我想做的是构建一个字符串类,如果传递一个静态字符串或指向一个的 constexpr 变量,它将简单地使用该指针,以后不会尝试删除它。

我认为我们在这里遇到了XY-problem。知道一个表达式是否是 constexpr 不会告诉你它是否适合 delete

我想说,如果这个操作可能不合适,该函数不应该尝试猜测是否删除。我相信调用者应该处理好这个问题,可能使用智能指针来处理这个问题。

换句话说,如果必须将指向的对象作为参数传递给函数,我会让函数接受左值引用,并让客户端取消对指针的引用。

我想说这种模式不仅仅在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() 转换为函数模板


最后,关于您最初关于如何确定表达式是否为常量表达式的问题,这通常是不可能的,但有一些技术可以在某些情况下帮助您 - 只需意识到他们的局限性。在这方面,您可能会发现this Q&A on StackOverflow 相关。

【讨论】:

  • 我很清楚地问了我想回答的问题。还是谢谢。
  • @CrazyEddie:如果是你投了反对票,我想得到一个解释。除了指出您的方法可能无法确定删除是否安全之外,我的回答还回答了您故意提出的问题,因为它为您指出了有关如何确定表达式是否为常量表达式的相关问答。
猜你喜欢
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
  • 2017-03-30
相关资源
最近更新 更多