I have a function in my code which only accepts a class member method as a template parameter. I need to call this method using a class method which is inherited from a parent class. Here is an example code of my problem:
template <class C>
class Test {
public:
template<typename R, R( C::* TMethod )()> // only a member function should be accepted here
void test() {}
};
class A {
public:
int a() { return 0; } // dummy method for inheritance
};
class B : public A {
public:
using A::a; // A::a should be declared in the B class declaration region
// int a() { return A::a(); } // if this lines is activated compliation works
};
int main() {
auto t = Test<B>();
t.test<int, &B::a>();
}
With the MSVC 2019 compiler the code compiles without problems. However the gcc produces following error:
<source>: In function 'int main()':
<source>:23:23: error: no matching function for call to 'Test<B>::test<int, &A::a>()'
23 | t.test<int, &B::a>();
| ~~~~~~~~~~~~~~~~~~^~
<source>:5:10: note: candidate: 'template<class R, R (B::* TMethod)()> void Test<C>::test() [with R (C::* TMethod)() = R; C = B]'
5 | void test() {}
| ^~~~
<source>:5:10: note: template argument deduction/substitution failed:
<source>:23:17: error: could not convert template argument '&A::a' from 'int (A::*)()' to 'int (B::*)()'
23 | t.test<int, &B::a>();
|
As far as I understand the gcc is still handling the type of B::a as A::a. On the cpp reference its saying that using
Introduces a name that is defined elsewhere into the declarative region where this using-declaration appears.
So in my opinion the using should transfer the A::a method to the declerativ region of B and therefor it should be handled as B::a. Am I wrong or is there a bug in GCC?
Here is the example on Compiler Explorer: https://godbolt.org/z/TTrd189sW
There is namespace.udecl, item 12 (emphasis mine):
For the purpose of forming a set of candidates during overload resolution, the functions named by a using-declaration in a derived class are treated as though they were direct members of the derived class. [...] This has no effect on the type of the function, and in all other respects the function remains part of the base class.
Thus, a is not a member of B, and the type of &B::a is int (A::*)().
(&B::a means the same thing regardless of whether you include using A::a; or not)
There is no point to using named functions from a base class except to work around the "hiding problem" when you want to overload or override them.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With