Can't assign non-const member function ptr to const one?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <type_traits>

struct Test
{
	void f(){}
	void g() const {}
};

int main()
{
	//outputs false
	std::cout << std::boolalpha
	          << std::is_assignable<void (Test::*)() const, void (Test::*)()>::value
	          << std::endl;
	void (Test::*mfp)() const = &Test::f; //does not compile
}
But why? What's wrong with having a pointer-to-const-member-function pointing to a non-const member function?
same as having a pointer to int pointing to a double. A const member function is not a const-qualified function (those don't exist, anyway), it's a different type entirely.
Why are they disparate types? In all other places in C++, a non-const may be implicitly converted to a const - why is it inconsistent here? (I'm not talking about the pointer variable itself, which would indeed be implicitly convertible to const.)

What I mean is, what technical reasons are there for not allowing this conversion? Would I be able to safely do it manually?
Last edited on

(guarantees not to change object)* = (makes no such guarantee)*

See the logical problem?
Last edited on
"All other places is really just two, to quote cppreference,

A prvalue of type pointer to cv-qualified type T can be converted to prvalue pointer to a more cv-qualified same type T (in other words, constness can be added)

A prvalue of type pointer to member of cv-qualified type T in class X can be converted to prvalue pointer to member of more cv-qualified type T in class X.


This case isn't one of those two: there are no cv-qualified function types.
Duoas wrote:

(guarantees not to change object)* = (makes no such guarantee)*

See the logical problem?
I feel dumb, I meant the other way around. Reverse all my const and non-const.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <type_traits>

struct Test
{
	void f(){}
	void g() const {}
};

int main()
{
	//outputs false
	std::cout << std::boolalpha
	          << std::is_assignable<void (Test::*)(), void (Test::*)() const>::value
	          << std::endl;
	void (Test::*mfp)() = &Test::g; //does not compile
}
(makes no such guarantee)* = (guarantees not to change object)*
Last edited on
So after ten days, this is really inconveniencing me. Why can't I assign a const member function pointer to a non-const member function pointer?
The type system is too strict to allow calling functions with different calling signatures (in this case, void(const Test&) and void(Test&)) through the same pointer. Can't you convert both into function objects?
Last edited on
I am already doing that, but I would have to duplicate massive amounts of code just to account for the const variant.
closed account (o1vk4iN6)
You can look at it with maybe some different syntax:

http://ideone.com/mBj8Fd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <functional>

struct Test
{
	void f()       { std::cout << "f" << std::endl; }
	void g() const { std::cout << "g" << std::endl; }
};

int main() {
	
	std::function<void(Test&)>       f = &Test::f; 
	std::function<void(const Test&)> g = &Test::g;
	
	// C++ provides no conversion from const to non-const.
	
	// const int a;
	// int& b = a; // basically what you are trying to do.
	
	Test t;
	
	f(t);
	g(t);
	
	return 0;
}


e: this is why i only post in the lounge :/ this thread got buried under all the threads made by new accounts.

Couldn't you just create a templated function for that parts of the code that are the same ?
Last edited on
The problem is that my template functions act explicitly on member function pointers, and I don't know a way to allow the compiler to autogenerate my code for both const and non-const versions of member function pointers.
1
2
3
4
5
template<typename T, typename R, typename... Args>
void f(R (T::*)(Args...) /*const*/)
{
    //...
}
My code is pretty complex:
https://github.com/LB--/hSDK/blob/master/include/hSDK/Extension.hpp#L270
Last edited on
closed account (o1vk4iN6)
Well could use std::function and template it, your right though the way you are doing it i don't see a way you can possibly template out that const.

http://ideone.com/vD6cT2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <functional>

struct Test
{
	void f()       { std::cout << "f" << std::endl; }
	void g() const { std::cout << "g" << std::endl; }
};

template<typename T, typename... Args>
void DoCall(std::function<T> func, Args... args)
{
	func(args...);
}

int main() {
	
	Test t;
	
	DoCall<void(Test&)>(&Test::f, t);
	DoCall<void(const Test&)>(&Test::g, t);
	
	return 0;
}
Yeah, because I actually have to perform some checking and transformations on each argument type of the member function (auto-converting between std::string and char const *, for example). I guess for now I will just have to not support const member functions until I find a way.
closed account (o1vk4iN6)
Well you can still template the args out and do whatever black magic you gotta do with them ?

http://ideone.com/P6o6TH

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <functional>

struct Test
{
	void f()       { std::cout << "f" << std::endl; }
	void g() const { std::cout << "g" << std::endl; }
};

template<typename R, typename... FArgs, typename... Args>
void DoCall(std::function<R (FArgs...)> func, Args... args)
{
	// do stuff with FArgs and Args...
	func(args...);
}

template<typename R, typename T, typename... Args>
std::function<R (T&, Args...)> make_function(R (T::* fptr)(Args...)) { return fptr;}

template<typename R, typename T, typename... Args>
std::function<R (const T&, Args...)> make_function(R (T::* fptr)(Args...) const) { return fptr;}


int main() {
	
	Test t;
	
	DoCall(make_function(&Test::f), t);
	DoCall(make_function(&Test::g), t);
	
	return 0;
}
Lines 18 and 21 in that example are hundreds of lines for me, no can do.
Last edited on
closed account (o1vk4iN6)
Lines 18 and 21 are templates and simply to cast a pointer to a function into a std::function type so you don't have to set the DoCall template parameters.

Any work you do with the template arguments is going to happen in DoCall.
Topic archived. No new replies allowed.