default null values for template member function pointers

Aug 30, 2010 at 1:46pm

Given the following template classes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<void (*init)() = 0> 
struct funct_ptr {
	void call() { 
		if(init) (*init)();
	}
};

template<typename T, void (T::*init)() = 0> 
struct mem_ptr {
	void call(T& targ) {
		if(init) (targ.*init)();
	}
};

struct target {
	static void static_fun() {}
	void member_fun() {}
};


All of the following compiles and runs fine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void testmethod() {
	// explicit value
	funct_ptr<&target::static_fun> fp;
	fp.call();

	// default to null
	funct_ptr<> fp1;
	fp1.call();

	// explicit value
	mem_ptr<target, &target::member_fun> mp;
	mp.call(target());

	// explicit null
	mem_ptr<target, 0> mp;
	mp.call(target());

}


But this one does not:

1
2
3
	// default to null - fails.
	mem_ptr<target> mp1;
	mp1.call(target());


Failing with:
error C2975: 'init' : invalid template argument for 'property::mem_ptr', expected compile-time constant expression



Is this a shortcoming in VC++ or is this somehow not standard compliant?
Last edited on Aug 30, 2010 at 11:30pm
Aug 30, 2010 at 9:41pm
You can only pass constants to template parameters. This means only Data types (including classes), const variables, and pure numbers/macros that define numbers.
Aug 30, 2010 at 11:30pm
And methods too, which are constants.
Last edited on Aug 30, 2010 at 11:30pm
Aug 31, 2010 at 12:57pm
You should consider using boost::function and boost::bind to do this.

1
2
3
4
5
6
7
8
9
10
11
12
#include <boost/bind.hpp>
#include <boost/function.hpp>

boost::function< void() > free_fn( boost::bind( &free_function ) );
boost::function< void() > static_mem_fn( boost::bind( &object::static_member_function ) );
boost::function< void() > functor( boost::bind( &instance_of_object_with_func_call_operator ) );
boost::function< void() > member_fn( boost::bind( &object::member_function, &instance_of_object ) );

free_fn();
static_mem_fn();
functor();
member_fn();

Last edited on Aug 31, 2010 at 12:57pm
Aug 31, 2010 at 3:05pm
Was hoping someone would have a good answer for this - after a quick look I wasn't able to definitively figure it out either. FWIW, on gcc 3.4.3, even the line mem_ptr<target, 0> mp; fails to compile. I believe the compiler has special logic to initialize a member function pointer with integer '0', which is in general is not legal due to the difference in size between the 2 data types. Maybe the logic to handle this only works for normal initialization, but fails when used in the context of a constant template parameter (although in your case, VC++ is allowing the explicit value 0, but not the default param, which is odd).

Looking at the spec, it seems like both should be legal, based on 4.11:

A null pointer constant (4.10) can be converted to a pointer to member type; the result is the null member pointer
value of that type and is distinguishable from any pointer to member not created from a null pointer constant. Two null
member pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to
member of cv-qualified type is a single

So my vote is for compiler error :)

--Rollie
Last edited on Aug 31, 2010 at 8:11pm
Sep 1, 2010 at 1:01am

Rollie:

I've submitted this as a bug report to the VC++ team.

It seems hard to see how this can be anything BUT a compiler bug. I've tried using (void*)(0) as the default, and even (void (T::*)())(0) and they don't work either.

Looks like g++ has something similar. Maybe this could be submitted there too.


jsmith:

I'm aware of the boost solution, and am in fact using it for the case in quesiton. It has some benifits and some detrements, but I won't go into those here.
Sep 1, 2010 at 1:01am
Topic archived. No new replies allowed.