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

Nov 16, 2013 at 1:17am
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?
Nov 16, 2013 at 1:30am
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.
Nov 16, 2013 at 1:36am
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 Nov 16, 2013 at 1:36am
Nov 16, 2013 at 1:44am

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

See the logical problem?
Last edited on Nov 16, 2013 at 1:44am
Nov 16, 2013 at 1:53am
"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.
Nov 16, 2013 at 1:59am
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 Nov 16, 2013 at 2:02am
Nov 25, 2013 at 10:59pm
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?
Nov 25, 2013 at 11:32pm
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 Nov 25, 2013 at 11:32pm
Nov 25, 2013 at 11:48pm
I am already doing that, but I would have to duplicate massive amounts of code just to account for the const variant.
Nov 26, 2013 at 12:00am
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 Nov 26, 2013 at 12:13am
Nov 26, 2013 at 12:45am
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 Nov 26, 2013 at 12:46am
Nov 26, 2013 at 1:08am
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;
}
Nov 26, 2013 at 1:39am
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.
Nov 26, 2013 at 1:56am
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;
}
Nov 26, 2013 at 6:52am
Lines 18 and 21 in that example are hundreds of lines for me, no can do.
Last edited on Nov 26, 2013 at 6:52am
Nov 26, 2013 at 2:59pm
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.