简体   繁体   中英

template argument deduction for function pointer (g++ & ICC vs Clang++ & VC++ )

Consider following program:

#include <iostream>
template <typename T>
void foo(const T* x) {
    x();
}
void bar() { std::cout<<"bar() is called\n"; }
int main() {
    foo(bar);
}

It compiles fine on clang++ & VC++ but g++ gives following compiler error (See live demo here )

main.cpp: In function 'int main()':
main.cpp:10:9: error: no matching function for call to 'foo(void (&)())'
  foo(bar);
         ^
main.cpp:3:6: note: candidate: template<class T> void foo(const T*)
 void foo(const T* x) {
      ^~~
main.cpp:3:6: note:   template argument deduction/substitution failed:
main.cpp:10:9: note:   types 'const T' and 'void()' have incompatible cv-qualifiers
  foo(bar);
         ^

I've used -pedantic-errors when using g++ & clang++ and I've used /W4 & /Za option when using VC++ compiler. See live demo here & here . So, I want to know how template type parameter T will be deduced here ? If I remove const from the program then it compiles fine on g++ also. If I use const T& then it compiles fine on all 3 compilers. So, how exactly type will be deduced here in these cases ?

Update:

This program fails in compilation on Intel C++ compiler also. See live demo here . So, is this bug in g++ & Intel C++ or bug in Clang++ & VC++ ?

This is essentially CWG issue 1584 :

It is not clear whether the following is well-formed or not:

 void foo(){} template<class T> void deduce(const T*) { } int main() { deduce(foo); } 

Implementations vary in their treatment of this example.

Which is currently still active. It's not really possible to say which compiler is right. Though as the note from 2015 indicates, the consensus in the CWG is currently that this should be rejected.


To give a little more context, we must remember that a function type with a cv-qualifier-seq has special meaning (think member functions), and is not simply a type the designates something which may not be modified. Moreover, you can't even add the cv qualification in some sneaky manner, as [dcl.fct]/7 illustrates:

The effect of a cv-qualifier-seq in a function declarator is not the same as adding cv-qualification on top of the function type. In the latter case, the cv-qualifiers are ignored. [ Note: A function type that has a cv-qualifier-seq is not a cv-qualified type; there are no cv-qualified function types. — end note ][ Example:

 typedef void F(); struct S { const F f; // OK: equivalent to: void f(); }; 

— end example ]

There is no way in the language to form a const qualified function type. And yet, the deduction we need is to have const T deduced as void() . The former is a const qualified type, and it must also be a function type. But that's a type that cannot exist! So how can it be deduced?!

On the other hand there is machinery in the standard to deduce it if you were using a reference instead of a pointer.

So it isn't that clear how this should be resolved. On the one hand the wording today doesn't allow it per-se, but on the other hand machinery for it is already in place for references. So some implementations go ahead and do the same for pointers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM