将const成员函数转换为非const

5

在C++中,成员函数指针的const属性如何确定?以下代码是否有效?

struct T {
  void foo(int i) const { std::cout << i << std::endl;};
};

void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int)       = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1);

更新:

我需要这个的原因是,我正在编写一个函数,它既接受对象,也接受指向该对象的成员函数指针。我需要一个版本来处理const对象(只接受const函数),还需要一个普通版本。由于我不想重复编写代码,我的想法是将实际代码放在非const版本中,并从const版本中调用它,消除任何const。


2
即使它被定义了,你也不应该这样做。const变量之所以是const,是有原因的。 - Gir
1
@Gir,并不是那么简单。在变量上强制转换去除const属性基本上是试图“增加可写性”(即提高期望),而在此方法上去除const属性则试图“解除函数必须提供‘我不会改变内部状态’保证”的限制(即降低期望)。 - Joachim Isaksson
2
@Gir 但是这些不是变量。当应用于函数时,您似乎没有理解“const”关键字的含义。 - user529758
@klm123:这不会改变任何事情。const是C++程序的语法糖,除非你像“static const int i = 1;”那样使用它。否则它可能会被优化掉,除非你在某个地方写了“&i”,否则它不会。对于函数来说更是如此。你不能传递任何将被优化掉的东西给一个函数,所以你可以毫不顾忌地在函数内外强制转换任何const。 - Evan Dark
如果您提供这些函数的示例以及如何使用它们,讨论将更加方便。 - klm123
显示剩余5条评论
5个回答

3
编译器吃掉它。但是向后转换更有用。再说一遍,但最好不要使用它,const_cast通常只是一个快速而肮脏的解决方案,只有在没有其他解决方案时才应用它。回答更新:如果我理解正确,您将使用一个对象和两个函数。第一个函数接受const对象和const成员函数,第二个函数接受非const对象和非const成员函数。根据给定的信息,您可以将第二个函数更改为接受非const对象和const成员函数,并给它们一个非const对象及其const成员函数。

1

是的,它已经被定义了,但如果函数确实是const的话,您可能不想要它,因为某些编译器优化(即返回值缓存)依赖于函数是const的。


0

你可以这样做,但它没有意义,无论你在哪里调用f2,你也可以调用f1。你应该以另一种方式进行转换。但如果有什么问题,你应该转换对象,而不是函数。

void (T::*f1)(int) const = &T::foo;
void (T::*f2)(int)       = reinterpret_cast<void (T::*)(int)>(f1);
T t;
(t.*f2)(1); // compiles
(t.*f1)(1); // this compiles too!!

但是如果你有

const T t;
(t.*f2)(1); // error t is const
(t.*f1)(1); // still compiles

0
唯一解决歧义的方法是执行 static_cast,这基本上是一种语言特性。
#include <boost/typeof/typeof.hpp>
struct Test
{
    const int& foo();
    const int& foo() const;
};

int main()
{
    typedef const int&(Test::*non_const_ptr)();
    typedef const int&(Test::*const_ptr)()const;
    BOOST_TYPEOF(static_cast<non_const_ptr>(&Test::foo)) ss;
}

-1

我不认为这样做有什么理由:即使你能够这样做,也会使它更加受限制。

假设你有一个类Foo:

class Foo {
  void f() const;
  void g();
}

以下是一些代码片段:

Foo a;
const Foo b;

然后你可以调用a.f()a.g(),但不能调用b.g(),因为bconst。正如你所看到的,将const放在成员函数之后使其更不受限制,而不是更受限制。

通过reinterpret_cast这个指针,你会得到具有完全相同值的指针(由于reinterpret_cast的性质),如果你尝试调用它,你将进入相同的T::foo()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接