I have a code snippet that works using GCC but not MSVC. It's a simplified block generated with Boost Fusion. Is there anything wrong with the code?
using namespace std;
template<typename T, size_t N>
struct struct_member_mptr;
template<auto mptr>
void callback() {
cout << "No callback for " << typeid(mptr).name() << endl;
}
template<typename T>
void func(T &u) {
callback<struct_member_mptr<T, 0>::value>();
callback<struct_member_mptr<T, 1>::value>();
}
struct Data {
int a;
char b;
};
template<>
struct struct_member_mptr<Data , 0> {
typedef decltype(Data::a) Data::*type;
static constexpr type value = &Data::a ;
};
template<>
struct struct_member_mptr<Data , 1> {
typedef decltype(Data::b) Data::*type;
static constexpr type value = &Data::b ;
};
template<>
void callback<&Data::a>() {
cout << "postParse D::a" << endl;
}
template<>
void callback<&Data::b>() {
cout << "postParse D::b" << endl;
}
int main() {
Data i;
func(i);
}
The expected result is:
postParse D::a
postParse D::b
and I have it with GCC
But the result from MSVC is:
No callback for int Data::* __ptr64
No callback for char Data::* __ptr64
UPD From Vincent Saulue-Laborde: reduced case, the issue is reproducible at compile time
template<auto mptr>
constexpr int callback() {
return 0;
}
template<>
constexpr int callback<2>() {
return 5;
}
constexpr int v2 = 2;
static_assert(callback<v2>() == 5);
As Vincent Saulue-Laborde pointed out in the comments, the problem is that MSVC treats struct_member_mptr<Data, 0>::value as having type int Data::* const (with const qualification), while your specialization callback<&Data::a> expects a parameter of type int Data::* (without const). MSVC fails to match these as the same specialization.
Some workarounds that should work with both GCC and MSVC:
template<>
void callback<struct_member_mptr<Data, 0>::value>() {
cout << "postParse D::a" << endl;
}
template<>
void callback<struct_member_mptr<Data, 1>::value>() {
cout << "postParse D::b" << endl;
}
template<auto mptr>
void callback_impl() {
cout << "No callback for " << typeid(mptr).name() << endl;
}
template<auto mptr>
void callback() {
callback_impl<mptr>(); // This forces a new instantiation without const
}
template<typename T, T mptr>
void callback() {
cout << "No callback for " << typeid(mptr).name() << endl;
}
// Then in func:
template<typename T>
void func(T &u) {
using mptr_type_0 = typename struct_member_mptr<T, 0>::type;
using mptr_type_1 = typename struct_member_mptr<T, 1>::type;
callback<mptr_type_0, struct_member_mptr<T, 0>::value>();
callback<mptr_type_1, struct_member_mptr<T, 1>::value>();
}
template<auto V>
static constexpr auto nonconst_value = V;
template<typename T>
void func(T &u) {
callback<nonconst_value<struct_member_mptr<T, 0>::value>>();
callback<nonconst_value<struct_member_mptr<T, 1>::value>>();
}
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