在 C++我可以重置运算符的函数指针吗?

发布于 2024-11-26 19:41:09 字数 726 浏览 4 评论 0原文

在 C++ 中,我可以重置运算符的函数指针吗?

特别是我想将成员函数operator[]设置为使用(或不使用)边界检查。我尝试过,但没有成功:

这可能吗?如果是这样,有人可以纠正语法吗?

在 MyArrayClass.h 中:

class MyArrayClass {
public:
    bool CheckArrayBounds;
    float BoundsCheck(int i) {
        if (i<_size) 
            return _data[i]; 
        return TCpx(_INVALID); 
    }
    float NoBoundsCheck(int i) {
        return _data[i]; 
    }
    void UseBoundsCheck(bool State) {
        if (State) {
            float (operator[]) = &MyArrayClass::BoundsCheck;
        } else {
            float (operator[]) = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return _data[i]; };
};

In C++ can I reset the function pointer for an operator?

In particular I want to set the member function operator[] to use (or not use) bounds checking. I tried this with no luck:

Is this even possible? If so, Can anyone correct the syntax?

in MyArrayClass.h:

class MyArrayClass {
public:
    bool CheckArrayBounds;
    float BoundsCheck(int i) {
        if (i<_size) 
            return _data[i]; 
        return TCpx(_INVALID); 
    }
    float NoBoundsCheck(int i) {
        return _data[i]; 
    }
    void UseBoundsCheck(bool State) {
        if (State) {
            float (operator[]) = &MyArrayClass::BoundsCheck;
        } else {
            float (operator[]) = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return _data[i]; };
};

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

椒妓 2024-12-03 19:41:09

这是不可能的。从语义上讲,成员函数不是函数指针(尽管它们可能在幕后以这种方式实现)。

您可以在 operator[] () 内执行对 State 的检查,或使用代理对象。

This is not possible. Semantically speaking, member functions are not function pointers (although they may be implemented that way under the hood).

You could perform the check on State inside operator[] (), or use a proxy object.

当梦初醒 2024-12-03 19:41:09

您无法在运行时更改特定对象实例的运算符,因为成员函数与对象属性分开存储,并且对于所有对象实例都是相同的。它们存储在写保护的内存段中。或者甚至可以由编译器内联。

您仍然可以检查operator[]实现内部的状态。

您还可以创建属性 at 并替换运算符。

class MyArrayClass {
public:
    float (MyArrayClass::*at)(int i);
    float BoundsCheck(int i);
    float NoBoundsCheck(int i); {
    void UseBoundsCheck(bool State) {
        at = (State)? &MyArrayClass::BoundsCheck : &MyArrayClass::NoBoundsCheck;
    }
};

用法:

MyArrayClass a;
a.at( 1 );

You cannot change operator for particular object instance in runtime because member functions are stored separately from object attributes and are the same for all object instances. And they are stored in write-protected memory segment. Or could even be inlined by the compiler.

Still you can check for state inside of the operator[] implementation.

Also you can create attribute at and replace operator.

class MyArrayClass {
public:
    float (MyArrayClass::*at)(int i);
    float BoundsCheck(int i);
    float NoBoundsCheck(int i); {
    void UseBoundsCheck(bool State) {
        at = (State)? &MyArrayClass::BoundsCheck : &MyArrayClass::NoBoundsCheck;
    }
};

Usage:

MyArrayClass a;
a.at( 1 );
凌乱心跳 2024-12-03 19:41:09

不。

方法(以及只是方法/函数的语法糖的运算符)是在编译时而不是运行时定义的。

No.

Methods (and operators which are just syntactic sugar for methods/functions) are defined at compile time not run time.

°如果伤别离去 2024-12-03 19:41:09

不幸的是,C++ 并不是适合这种情况的语言。您需要一个更强大的类型系统。

请注意,即使可以,您可能会减慢程序速度:整数比较比通过指针调用函数要昂贵得多。特别是因为你的 CPU 可以进行分支预测:它将开始运行代码,就像它通过了检查一样,如果它最终失败,它可以放弃它正在做的任何事情。

但请注意您的编译器是智能的。例如,如果我们有这样的:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <vector>

void process(std::vector<int>& data)
{
    for (unsigned i = 0; i < data.size(); ++i)
    {
        int v = data.at(i);
        std::cout << v << std::endl;
    }
}

int main()
{
    try
    {
        std::vector<int> data;
        std::generate_n(std::back_inserter(data), std::rand() + 1, std::rand);

        process(data);
    }
    catch (...)
    {
        std::cerr << "nope.avi" << std::endl;
    }
}

如果我们使用 g++ -O3 进行编译,则没有边界检查代码。事实上,编译器已经推断出 at() 内部的检查永远不会通过(然后抛出),因此它删除了该代码。因此,您可以保留边界检查,而编译器仍然可以将其剥离。但请注意,任何更复杂的情况可能会使编译器难以证明,因此您将为此付出代价。

这些是您可以通过更具表现力的类型系统保证的优化,但编译器无论如何都可以做到这些。我不知道MSVC;它往往不那么聪明,但你可以检查一下。

最好的选择是采用 std::vector<> 路线:提供未经检查的 operator[] 和经过检查的 at()。让您班级的用户决定他们是否需要检查。

C++ isn't the right kind of language for this, unfortunately. You need a much more powerful type system.

Note that even if you could, you'd probably slow your program down: a integer comparison is much more expensive that a function call through a pointer. Especially since your CPU can branch predict: it'll start running code as if it passed the check, and if it ends up failing it can ditch whatever it was doing.

But note your compiler is smart. For example, if we have this:

#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <vector>

void process(std::vector<int>& data)
{
    for (unsigned i = 0; i < data.size(); ++i)
    {
        int v = data.at(i);
        std::cout << v << std::endl;
    }
}

int main()
{
    try
    {
        std::vector<int> data;
        std::generate_n(std::back_inserter(data), std::rand() + 1, std::rand);

        process(data);
    }
    catch (...)
    {
        std::cerr << "nope.avi" << std::endl;
    }
}

And if we compile with g++ -O3, there is no bounds checking code. Indeed, the compiler has deduced that the check inside at() will never pass (which then throws), so it stripped away that code. So you can leave the bounds checking in and your compiler can still strip it away. Note, though, that any more complex cases may make it too hard for the compiler to prove, so you'll pay for it.

These are the kind of optimizations you could guarantee with a more expressive type system, but the compiler can do them anyway. I don't know about MSVC; it tends not to be as smart, but you can check.

Your best bet is to go the std::vector<> route: provide an unchecked operator[] and a checked at(). Let the user of your class decide if they need checks or not.

浪漫人生路 2024-12-03 19:41:09

函数和成员函数实际上是常量和不可变的,并且不可能在运行时更改它们。然而,对于您想要做的事情来说,有一种半途而废的方法,而且您在发布的代码中几乎已经完成了。

您可以做的是定义一个指向成员函数的指针,然后根据您是否希望边界检查处于活动状态在运行时更改指针值。

class MyArrayClass {
public:
    typedef float (MyArrayClass::*AccessFn)(int i);
    AccessFn Access;
    bool CheckArrayBounds;

    float BoundsCheck(int i) {
        if (i<_size)
            return _data[i];
        return TCpx(_INVALID);
    }
    float NoBoundsCheck(int i) {
        return _data[i];
    }

    MyArrayClass() { UseBoundsCheck(false); }

    void UseBoundsCheck(bool State) {
        if (State) {
            Access = &MyArrayClass::BoundsCheck;
        } else {
            Access = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return (this->*Access)(i); }
};

这是我能想到的最接近您要求的方法。

Functions and member functions are effectively constant an immutable, and it is not possible to change them at runtime. However, there's a kind of half-way house to what you are trying to do, and you were almost there in your posted code.

What you can do is define a pointer to a member function, and then alter the pointer value at runtime depending on whether you want bounds checking active or not.

class MyArrayClass {
public:
    typedef float (MyArrayClass::*AccessFn)(int i);
    AccessFn Access;
    bool CheckArrayBounds;

    float BoundsCheck(int i) {
        if (i<_size)
            return _data[i];
        return TCpx(_INVALID);
    }
    float NoBoundsCheck(int i) {
        return _data[i];
    }

    MyArrayClass() { UseBoundsCheck(false); }

    void UseBoundsCheck(bool State) {
        if (State) {
            Access = &MyArrayClass::BoundsCheck;
        } else {
            Access = &MyArrayClass::NoBoundsCheck;
        }
        CheckArrayBounds = State;
    }
    float operator[](int i) { return (this->*Access)(i); }
};

This is the closest way of doing what you've requested that I can think of.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文