We have a problem porting our code to the slightly less old version 2010 of VC++.
The issues is caused by the implementation of map in VC which results in a derived to base conversion of a pointer-to-member
in a non-type-argument
being required:
#include <map>
#include <algorithm>
template <typename MapValueType, int MapValueType::*var>
bool f (MapValueType const & v);
int main ()
{
typedef std :: map<int, int> MapType;
MapType m;
std :: find_if (m.begin ()
, m.end ()
, f<MapType::value_type, & MapType::value_type::second> );
}
The following message is generated:
Standard conversion from pointer-to-member of base to pointer-to-member of derived is not applied for template arguments file.cc(x) : error C2973: 'f' : invalid template argument 'int std::_Pair_base<_Ty1,_Ty2>::* '
So it seems that the implementation of value_type
in std::map
has the pair in a base class.
Any ideas on how to solve this and keep the pointer-to-member
as a non-type-argument
?
Is our only option to change the structure so that f
is a functor
with a member pointer-to-member
?
Why do you insist on keeping the pointer-to-member as non-type-template parameter/argument?
Anyway, I think that you could use this, if you can be limited to either Visual Studio 2010 or compilers with decltype()
template <typename Class, typename Type>
Class
get_class_type (Type Class:: *);
//...
it = std::find_if(m.begin(), m.end(),
f<decltype(get_class_type(&MapType::value_type::second)), &MapType::value_type::second>);
Provided that your code should compile IMO (and it does on GCC 4.7.2 and Clang 3.2), I believe your design is unnecessarily intricate. A pair
only has two member variables, so you are going to access either the first or the second.
I do not see the need for a functor object either: just use a boolean template argument to determine whether the code shall work on the first
or on the second
member variable.
Here's a possibility:
#include <map>
#include <algorithm>
template <typename MapValueType, bool first>
bool f (MapValueType const & p)
{
auto& v = (first) ? p.first : p.second;
// ... do your work on v ...
}
int main ()
{
typedef std :: map<int, int> MapType;
MapType m;
// Will work on the `first` member
std::find_if(m.begin (), m.end (), f<MapType::value_type, true>);
// Will work on the `second` member
std::find_if(m.begin (), m.end (), f<MapType::value_type, false>);
}
If you really cannot change your client code nor your code inside the f()
function, then you could go for this VS2010-specific hack:
// Add "_MyBase" here... works, but ugly IMO
template <typename MapValueType, int MapValueType::_Mybase::* var>
bool f(MapValueType const & v);
// And the client side could stay unchanged...
int main ()
{
typedef std :: map<int, int> MapType;
MapType m;
std::find_if(
m.begin(),
m.end (),
f<MapType::value_type, &MapType::value_type::second>
);
}
Finally, if your code has to compile on other platforms and all the constraints on the non-modifiability of the function's and client code still hold, then you can define a preprocessor macro that expands to _Mybase::
for VS2010 and to the empty string for other compilers.
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