I have example code which compiles under C++14 fine on GCC/Clang/MSVC, and under C++17 on Clang/MSVC, yet under C++17 on GCC 8.x through 10.1 it produces an error.
#include <vector> // vector
template< typename Seq,
typename Seq::value_type& ( Seq::*next )(),
void ( Seq::*pop )() >
void f( Seq& );
template< typename Seq >
void g( Seq& seq )
{
f< Seq, &Seq::back, &Seq::pop_back >( seq );
}
void foo()
{
std::vector< int > v;
g( v );
}
I receive the following error from GCC 10.1 using CXXFLAGS=-std=c++17
:
<source>: In instantiation of 'void g(Seq&) [with Seq = std::vector<int>]':
<source>:17:10: required from here
<source>:11:41: error: no matching function for call to 'f<std::vector<int, std::allocator<int> >, (& std::vector<int, std::allocator<int> >::back), &std::vector<int, std::allocator<int> >::pop_back>(std::vector<int>&)'
11 | f< Seq, &Seq::back, &Seq::pop_back >( seq );
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
<source>:6:6: note: candidate: 'template<class Seq, typename Seq::value_type& (Seq::* next)(), void (Seq::* pop)()> void f(Seq&)'
6 | void f( Seq& );
| ^
<source>:6:6: note: template argument deduction/substitution failed:
<source>:11:41: error: 'int& (std::vector<int>::*)(){((int& (std::vector<int>::*)())std::vector<int>::back), 0}' is not a valid template argument for type 'int& (std::vector<int>::*)()'
11 | f< Seq, &Seq::back, &Seq::pop_back >( seq );
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~
<source>:11:41: note: it must be a pointer-to-member of the form '&X::Y'
Compiler returned: 1
I know the second parameter, &Seq::back
is an overloaded function; I created a intermediate member function pointer of the non-const overload, and passed that as the second argument to call f
, yet I receive near identical errors.
So, the basic questions are, is this invalid C++17 code, or is this a GCC bug? Presuming it's invalid C++17, how would I make it valid?
Bonus question: what is 'int& (std::vector<int>::*)(){((int& (std::vector<int>::*)())std::vector<int>::back), 0}'
? I'm completely surprised by the {
/}
pair, and the 0
. I know the outer part is the method signature, and the inner first part is casting the overloaded method to the expected signature, but why the {
/}
pair and the 0
? An initializer list? A struct? The internals of a member pointer?