Reputation: 63
Weird problem on a kind of retro environment. I'm coding against a given library with GCC 4.8.2 in gnu++11 mode. The library has this kind of interface code:
template<class somecls>
class LibraryInterface
{
public:
template<class var>
void someFunc(somecls *obj, var somecls::* member)
{
std::cout << "doing some nice computations on [" << obj->*member << "] ..." << std::endl;
}
};
This works perfectly fine with code like this:
class Base1
{
public:
std::string member1;
};
int main()
{
LibraryInterface<Base1> lib_if;
Base1 my_var;
my_var.member1 = "data1";
lib_if.someFunc(&my_var, &Base1::member1);
}
But when things got more complex, I wanted to use a class which derives from two other classes having the required members. The base classes are split up because there's also the need (in some other use cases) to use the two base classes on their own. So I ended up with something like this:
class Base1
{
public:
std::string member1;
};
class Base2
{
public:
std::string member2;
};
class Child : public Base1, public Base2
{
// just a class which holds members of both base classes
};
int main()
{
LibraryInterface<Child> lib_if;
Child my_var;
my_var.member1 = "data1";
my_var.member2 = "data2";
lib_if.someFunc(&my_var, &Child::member2);
}
However, GCC does not like this and gives me the following:
template.cpp: In function 'int main()':
template.cpp:37:42: error: no matching function for call to 'LibraryInterface<Child>::someFunc(Child*, std::string Base2::*)'
lib_if.someFunc(&my_var, &Child::member2);
^
template.cpp:37:42: note: candidate is:
template.cpp:8:7: note: template<class var> void LibraryInterface<somecls>::someFunc(somecls*, var somecls::*) [with var = var; somecls = Child]
void someFunc(somecls *obj, var somecls::* member)
^
template.cpp:8:7: note: template argument deduction/substitution failed:
template.cpp:37:42: note: mismatched types 'Child' and 'Base2'
lib_if.someFunc(&my_var, &Child::member2);
Of course I could always just create a third class and copy and paste all the members from Base1 and Base2 into it, but I'd like to keep things nice and tidy. Having the class hierarchy would give the benefit of automatically having new members of the base classes without having to copy and paste (urgh!) again.
I really don't know what to do here. Current MSVC is fine with that code, but even GCC 9.3.0 gives the same errors as GCC 4.8.2. There is no possibility to change the library code - it's a given. I could rewrite my own (the non-template) code of course, if it would help. Maybe there's some cmdline flag which convinces GCC to accept this piece of code?
Thanks in advance for any hints!
Upvotes: 2
Views: 44
Reputation: 1941
Here is you solution. It works on GCC, CLang and MSVC.
int main()
{
LibraryInterface<Child> lib_if;
Child my_var;
my_var.member1 = "data1";
my_var.member2 = "data2";
lib_if.someFunc(&my_var, static_cast<std::string Child::*>(&Child::member2));
}
The standard states that the type of the expression address-of-member is a pointer to a member of the class that declares the member, and not a pointer to a member of the class in the qualified-id.
The problem is very well described in this link: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3772.pdf
Upvotes: 2