How do I get the following code to compile?
I realize that the compiler is not happy with V<double>
because it tries to compile my typedef for GetterFn
, but I would like GetterFn
and GetCalc()
to be available for classes, but ignored for primitive types.
How should I recode this class?
#include <vector>
using namespace std;
class Bar
{
public:
float getMyFloat() const { return 42.5; }
};
template< typename T >
class V
{
public:
typedef float (T::*GetterFn)() const;
void getCalc( std::vector<double>& vec, GetterFn fn ) const
{
vec.clear();
for ( size_t i=0; i<m_v.size(); ++i )
vec.push_back( m_v[ i ].*(fn)() );
}
private:
vector<T> m_v;
};
int main(int argc, char** argv)
{
V<Bar> vb; // ok
V<double> vd; // compiler not happy
}
Alf's slightly snarky answer is indeed the easiest way. Instead of having the GetterFn
be a member function pointer, just use an overloaded free function to get the value:
void getCalc( std::vector<double>& vec) const
{
vec.clear();
for ( size_t i=0; i<m_v.size(); ++i )
vec.push_back( get_value(m_v[ i ]) );
}
and then just overload get_value
appropriately:
double get_value(double value) { return value; }
double get_value(Bar value) { return value.getMyFloat(); }
Of course, a more descriptive name than get_value
is highly recommended.
A double
cannot have a member function. Ergo, use a non-member function.
It's a bit hard to suggest the complete solution without knowing what you want to do for fundamental types. However, at the heart I suggest you employ the std::is_fundamental
type trait.
If you want entire collections of member functions to exist only conditionally, then perhaps wrapping them into a member helper class is one idea:
#include <vector>
#include <type_traits>
#include <cstddef>
class Bar
{
public:
float getMyFloat() const { return 42.5; }
};
template< typename T >
class V
{
private:
static const bool m_primitive = std::is_fundamental<T>::value; // convenience
template <bool B, typename U> struct Helper;
template <typename U> struct Helper<false, U>
{
typedef float (T::*GetterFnType)() const;
void getCalc(std::vector<double> & v1, std::vector<U> const & v2, GetterFnType f)
{
v1.clear();
for (std::size_t i = 0; i < v2.size(); ++i)
v1.push_back((v2[i].*f)());
}
};
public:
// use Helper<m_primitive, T>::GetterFn and Helper<m_primitive, T>::getCalc() here
private:
std::vector<T> m_v;
};
int main(int argc, char** argv)
{
V<Bar> vb; // ok
V<double> vd; // compiler also happy
}
You'll probably also have to do some std::enable_if
in the actual implementation. If you post more details, we can elaborate.
If you're open to a broader redesign, Konrad's answer feels like the final result would be somewhat cleaner and simpler, but then again I'm all in favour of convoluted template voodoo :-)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.