6

This code compiles OK on g++ (Coliru), but not Visual C++ (rextester) - both online and my desktop.

It is a simplified version of a much larger Visual Studio 2015 project.

class AAA{
    public: template<class T> static T*  test(T* hqi){
        return hqi;
    }
};
class TTT3{ 
    public: int d;   //In real case, it is some class, but same error nonetheless.
    decltype(AAA::test(&d)) dfd=AAA::test(&d);  //<-- error only Visual C++
};
int main(){
    int b;
    decltype(AAA::test(&b)) dfd=AAA::test(&b);  //OK for boths
}

'T *AAA::test(T *)': could not deduce template argument for 'T ' from 'int TTT3:: '

Question

  • Why? Is my code wrong? - I don't think so.
  • How to make it compile in Visual C++? I need it.
javaLover
  • 6,347
  • 2
  • 22
  • 67

2 Answers2

1

This doesn't look valid to me because the first &d in

decltype(AAA::test(&d)) dfd=AAA::test(&d);

is an implicit use of this outside of the member initializer. I can't find any exception in the Standard making an implicit use of this inside decltype valid, plus all three major compilers complain if you replace the &d with explicit &this->d.

Unfortunately, I don't see any easy way around this, unless you substitute the actual type of d or make a typedef for it.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • Thank. I doubt .... It would work if I change to `int* dfd=AAA::test(&d);`. Therefore, the problem is probably in `decltype` only. It should not compilable if your hypothesis is correct. (?) – javaLover May 01 '17 at 02:03
1

This is a Visual Studio specific bug. According to the standard:

[expr.unary.op/4]

A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed in parentheses. [ Note: That is, the expression &(qualified-id), where the qualified-id is enclosed in parentheses, does not form an expression of type “pointer to member”. Neither does qualified-id, because there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to member function” as there is from an lvalue of function type to the type “pointer to function” ([conv.func]). Nor is &unqualified-id a pointer to member, even within the scope of the unqualified-id's class. — end note ]

The text in bold is what VC++ doesn't do properly inside decltype for whatever reason. Since hoping that Microsoft will fix it is a fools hope, another workaround you can do is to add the following overload:

template<class C, typename T>
static T* test(T C::*);

Live Example

Possibly in a #ifdef/#endif block that checks for VC++. Not defining it prevents it being picked silently outside of an unevaluated context such as a decltype, albeit with only a link time error.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • I am interested in your thought process that you used to come up with this great solution. .... By the way, this is not the first time you help me, thank a lot. – javaLover May 09 '17 at 07:51
  • 1
    @javaLover - Well. Step 1 was to check the semantics of & according to the standard to see which compiler errs. Then I set out to force `decltype` to deduce the correct type without you having to change the definition of `dfd`. If VC++ wants to pass a pointer to member, I figured we'd accept it and return a regular pointer. At first I returned `nullptr`, but then figured deleting it would prevent subtle bugs. Then it was just a matter of checking if using deleted functions as unevaluated operands is okay, and it is. Thus the answer was sculpted. Hope this ramble is of help to you :) – StoryTeller - Unslander Monica May 09 '17 at 07:55
  • 1
    @javaLover - I amended the answer a bit. Please see the fixed part about deleting it. You shouldn't do that. It's ill-formed, I was wrong. – StoryTeller - Unslander Monica May 09 '17 at 08:05