Specifying address of member function template problem

Attempting to take the address of a member function template succeeds when the enclosing class is hardcoded but fails when it is passed to a template. The code:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
struct AType 
  {
  double SomeFunc(int,long *,double &) { double ret(0); return ret; }
  template<class X,class Y,class Z,short AA> double SomeFuncTemplate(X,Y *,Z &) { double ret(AA); return ret; }
  };

template
  <
  class T
  > 
struct TTest
  {
  typedef char Bad;
  struct Good { char x[2]; };
  template<T> struct helper;
  static Good check(helper<&AType::template SomeFuncTemplate<int,long,double,50> > *);
  static Bad check(...);
  static const bool value=sizeof(check(0))==sizeof(Good);
  };
  
template
  <
  class T,
  class C
  > 
struct TTest1
  {
  typedef char Bad;
  struct Good { char x[2]; };
  template<T> struct helper;
  template<class U> static Good check(helper<&U::SomeFunc> *);
  template<class U> static Bad check(...);
  static const bool value=sizeof(check<C>(0))==sizeof(Good);
  };
  
template
  <
  class T,
  class C
  > 
struct TTest2
  {
  typedef char Bad;
  struct Good { char x[2]; };
  template<T> struct helper;
  template<class U> static Good check(helper<&U::template SomeFuncTemplate<int,long,double,50> > *);
  template<class U> static Bad check(...);
  static const bool value=sizeof(check<C>(0))==sizeof(Good);
  };
  
int main()
  {
  
  static_assert(TTest
                  <
                  double (AType::*)(int,long *,double &)
                  >::value,
                "failure in TTest"
               );
            
  static_assert(TTest1
                  <
                  double (AType::*)(int,long *,double &),
                  AType
                  >::value,
                "failure in TTest1"
               );
            
  static_assert(TTest2
                  <
                  double (AType::*)(int,long *,double &),
                  AType
                  >::value,
                "failure in TTest2"
               );
            
  return 0;
  
  }


A static assert occurs for TTest2 of "failure in TTest2" but there is no static assert for TTest0 or TTest1. Tried wth gcc 4.5.2 and msvc 10.0.

The TTest1 shows that the same technique used in the failing TTest2 is used with a regular member function, and succeeds.

Why is this failure occuring ? Is it a bug in both compilers or is my code for TTest2 incorrect somehow ?
Think about it. What is the address of the following function in memory?

1
2
3
template< typename T >
T mul_by_2( T v )
{ return v + v; }


Well, if the application called this function in one place with T = int and in another with T = double, then there'd be two versions of mul_by_2 in memory, each with a different address.

So if you ask the compiler to give you the address of the function without specifying T, it can't know which one you want (indeed it can't even know which ones are available).
I am specifying all of the template parameters in my code above.
Sorry, I misread.

I looked at this further. Unfortunately, I don't think it works at all. In all cases, the parameter you pass to check is simply a hard-coded zero. The only question you are therefore asking is whether zero is convertible to C. I'm thinking that's not what you want to do?
Looks interesting.

I don't know why its not working, but I've never seen the syntax to specify a member function template before...

Well, I tried to shorten your problem until I couldn't think of any shorter version.. This is what I got:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct AType 
{
	template<class X> void SomeFuncTemplate() { }
};

template<void (AType::*)()> struct helper;

static void check1(helper<&AType::template SomeFuncTemplate<int> > *);
template<class U> static void check2(helper<&U::template SomeFuncTemplate<int> > *);

int main()
{
	check1(0);        // this line compiles fine
	check2<AType>(0); // this line does not compile. Why?
}


Maybe it helps someone else?
Ok. I don't get it. The first static assertion from the code below works, but the second doesn't.

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
struct AType
{
  template<class X,class Y,class Z,short AA> double SomeFuncTemplate(X,Y *,Z &) { double ret(AA); return ret; }
};

typedef char Bad;
struct Good { char x[2]; };
template<double (AType::*)(int,long*,double&)> struct helper;

struct TTest1
{
  template<class U> static Good check(helper<&U::template SomeFuncTemplate<int,long,double,50> > *);
  template<class U> static Bad check(...);
  static const bool value=sizeof(check<AType>(0))==sizeof(Good);
};

template
<int>
struct TTest2
{
  template<class U> static Good check(helper<&U::template SomeFuncTemplate<int,long,double,50> > *);
  template<class U> static Bad check(...);
  static const bool value=sizeof(check<AType>(0))==sizeof(Good);
};

int main()
{
  static_assert(TTest1::value, "TTest1 failure");
  static_assert(TTest2<0>::value, "TTest2 failure");
}
Merely because the hosting type is template, it bugs.

Also, if I do comment the vararg like this:
1
2
3
4
5
6
7
8
template
<int>
struct TTest2
{
  template<class U> static Good check(helper<&U::template SomeFuncTemplate<int,long,double,50> > *);
  //template<class U> static Bad check(...);
  static const bool value=sizeof(check<AType>(0))==sizeof(Good);
};
it says, "error: no matching function for call to 'TTest2<0>::check(int)". This means that it doesn't feel that the Good check overload is appropriate.

If I cast the check argument like this:
1
2
3
4
5
6
7
8
template
<int>
struct TTest2
{
  template<class U> static Good check(helper<&U::template SomeFuncTemplate<int,long,double,50> > *);
  //template<class U> static Bad check(...);
  static const bool value=sizeof(check<AType>((helper<&AType::SomeFuncTemplate<int,long,double,50> > *)0))==sizeof(Good);
};
the error remains, but it changes to "error: no matching function for call to 'TTest2<0>::check(helper<&AType::SomeFuncTemplate>*)".

However, if I change the Good check like this, everything works peachy:
1
2
3
4
5
6
7
8
template
<int>
struct TTest2
{
  template<class U> static Good check(helper<&AType::template SomeFuncTemplate<int,long,double,50> > *);
  template<class U> static Bad check(...);
  static const bool value=sizeof(check<AType>(0))==sizeof(Good);
};
, which is not the point of course.

I also found out that I can not explicitly instantiate like this:
1
2
template Good TTest1::check<AType>(helper<&AType::SomeFuncTemplate<int,long,double,50> > *);
template Good TTest2<0>::check<AType>(helper<&AType::SomeFuncTemplate<int,long,double,50> > *);

I mean, the first one works (except that it can not find the definition, which is understandable), but the second instantiation barks "error: template-id 'check<AType>' for 'Good TTest2<0>::check(helper<&AType::SomeFuncTemplate>*)' does not match any template declaration".

Well, everyone knows there is adverse side to template meta-programming, but for learning sake...

Regards
Evidently neither VC++ or gcc can handle the correct code without reporting an error, but clang on Linux compiles it without a problem. I have since been told that my OP code is fine. Now I just need to find a workaround for VC++ ( 8,9,10 ) and gcc for the original code above. Both compilers have acknowledged it is a bug in their compiler ( reported on gcc Bugzilla and Microsoft Connect ).
Could the microsoft-specific command "__if_exists" be an alternative for VC++ for you?
Topic archived. No new replies allowed.