简体   繁体   中英

Function pointer reference parameter conversion to const

The sample code:

class Foo;
typedef void (*fnptr)(Foo &foo);
fnptr gFn;
void myfoo(const Foo &foo) {}

int main() {
    gFn = &myfoo;
}

Fails with the following error using clang:

main.cpp:9:9: error: assigning to 'fnptr' (aka 'void (*)(Foo &)') from incompatible type
      'void (*)(const Foo &)': type mismatch at 1st parameter ('Foo &' vs 'const Foo &')
    gFn = &myfoo;
        ^ ~~~~~~
1 error generated.

GCC also fails with a similar error. Passing a pointer instead of a reference also

I don't really understand why this is an error. A function accepting a const Foo& also accept a Foo& as argument and, in both cases, a pointer is passed down. I would like to understand why this is an error.

A function of the signature void(*)(const Foo&) is not the same as void(*)(Foo&) .

For example, you can pass rvalues to void myfoo(const Foo&) , but you can't to for the void myfoo(Foo&) . As, you know, such constraint on what you can pass are checked at compile-time for functions at the call site.

For the sake of sanity, those constraint are also checked on function pointers.

Example:

class Foo{};

using FooPtr = void(*)(Foo&);
using ConstFooPtr = void(*)(const Foo&);

void fooNonConst(Foo&) { }
void fooConst(const Foo&) { }


int main() {
    FooPtr ptr1 = &fooNonConst;
    ConstFooPtr ptr2 = &fooConst;

    ptr1(Foo{});   //Not OK
    ptr2(Foo{});   //Ok
}

The reason is simply because the standard mandates it . Why do we drive on the right in US and on the left in UK? Ok kind of joking, but not that much. There are quite a lot of corner cases like that, where we find ourselves thinking but why didn't they allow this or that? And sometimes what was disallowed in a version of the standard become allowed in a next one. For example in C++98, only static const integral members could be initialized in a class declaration, all other members should be initialized in a constructor. C++11 allows initialization of members in a class declaration.

But here what you ask for would probably make type safety controls harder for compilers, while they are already quite complex!

So the way to go here for a conformant program in to use a wrapper around myfoo :

void myfoo_wrap(Foo &foo) {
    myfoo(foo);
}

I must admit that this may look stupid, but the good news is that an optimizing compiler should be able to remove it from the executable. That means that is is lite in source and not noticiable in executable: I'm afraid that this rule will not be changed soon in standard...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM