[RESOLVED] Passing a function pointer as template argument to a class
Hi all,
I have in the past written code for templated functions where one function argument can be either a function pointer or a Functor. Works pretty straightforward.
Now I am in a situation where I am actually trying to pass a function pointer as template argument to a class. Unfortunately this does not work, I can pass the Functor class but not the function pointer. Below code illustrates the issue:
Code:
#include <string>
#include <iostream>
#include <sstream>
#include <cstdlib>
// For demonstration
const char * external_library_call() {
return "FFFF";
}
// Default conversion from const char * to native type. This shall be specialized!
template<typename T>
class StandardConverter
{
public:
T operator()(const char * str) {
std::istringstream is(str);
T t;
is >> t;
return t;
}
};
// Special conversion function. There might be many of these.
std::string hex2dec(const char * str) {
std::ostringstream os;
os << strtol(str, 0, 16);
return os.str();
}
// Field class
template<typename T, typename F = StandardConverter<T> >
class Field
{
private:
F f;
public:
T get()
{
return f(external_library_call());
}
};
// Record class
class Record
{
public:
Field<std::string> I_FIELD1;
Field<std::string, StandardConverter<std::string> > I_FIELD2;
// Field<std::string, hex2dec> I_FIELD3;
};
int main()
{
Record rec;
std::cout << rec.I_FIELD1.get() << std::endl;
std::cout << rec.I_FIELD2.get() << std::endl;
// std::cout << rec.I_FIELD3.get() << std::endl;
}
The idea is to have the definition of the Record class simple and readable and have a maintainable way to add auto-conversion functions to the class. So the lines I commented out are the desirable way how I want my code to look. Unfortunately I could not come up with any way that was close to readable for solving this.
Does anybody have any good suggestions?
Re: Passing a function pointer as template argument to a class
You could do something like this:
Code:
#include <string>
#include <iostream>
#include <sstream>
#include <cstdlib>
// For demonstration
const char * external_library_call() {
return "FFFF";
}
// Default conversion from const char * to native type. This shall be specialized!
template<typename T>
class StandardConverter
{
public:
T operator()(const char * str) {
std::istringstream is(str);
T t;
is >> t;
return t;
}
};
// Special conversion function. There might be many of these.
std::string hex2dec(const char * str) {
std::ostringstream os;
os << strtol(str, 0, 16);
return os.str();
}
// Field class
template<typename T, typename F = StandardConverter<T> >
class Field
{
private:
F f;
public:
Field() {}
explicit Field(F f_) : f(f_) {}
T get()
{
return f(external_library_call());
}
};
// Record class
class Record
{
public:
Record() : I_FIELD3(hex2dec) {}
Field<std::string> I_FIELD1;
Field<std::string, StandardConverter<std::string> > I_FIELD2;
Field<std::string, std::string (*)(const char*)> I_FIELD3;
};
int main()
{
Record rec;
std::cout << rec.I_FIELD1.get() << std::endl;
std::cout << rec.I_FIELD2.get() << std::endl;
std::cout << rec.I_FIELD3.get() << std::endl;
}
Re: Passing a function pointer as template argument to a class
... or to avoid laserlight's auxillary constructor and put the function name directly in the Field declaration, you could write something like
Code:
template<class Src, class Dst, Dst (*Fun)(Src) >
class FunctionConverter
{
public:
Dst operator()(Src src)
{
return Fun( src );
}
};
class Record
{
public:
Field<std::string> I_FIELD1;
Field<std::string, StandardConverter<std::string> > I_FIELD2;
Field<std::string, FunctionConverter<const char*,std::string,hex2dec> > I_FIELD3;
};
moreover, if I read your code correctly, Src should be fixed to "const char*", hence it could be omitted in the declaration. Then, you could also just write, say, "FunctionField<std::string, hex2dec> I_FIELD3;" ...
Re: Passing a function pointer as template argument to a class
Thanks Superbonzo!
I was trying the same approach, i.e. using a generic class to wrap around the function(s) but always ended up with the same problem, i.e. how to pass the function as a template argument, be it to the wrapper or to the Field class. Looking at your example I understood it is actually possible.
I modified the approach to not use Functors at all, which now allows for clean definition of the Record class. For those who care, an example is below.
Code:
#include <string>
#include <iostream>
#include <sstream>
#include <cstdlib>
// For demonstration
const char * external_library_call() {
return "1010";
}
// Default conversion from const char * to native type.
template<typename T>
T convert(const char * str)
{
std::cout << "Using generic (templated) convert function\n";
std::istringstream is(str);
T t;
is >> t;
return t;
}
// Specializations of convert
template<>
std::string convert<std::string>(const char * str)
{
std::cout << "Using specialization for std::string\n";
return str;
}
template<>
const char * convert<const char *>(const char * str)
{
std::cout << "Using specialization for const char *\n";
return str;
}
// Special conversion function. There might be many of these.
std::string hex2dec(const char * str) {
std::cout << "Using hex2dec function\n";
std::ostringstream os;
os << strtol(str, 0, 16);
return os.str();
}
template<typename T, T(*F)(const char *) = convert<T> >
class Field
{
public:
T get()
{
return F(external_library_call());
}
};
// Record class
class Record
{
public:
Field<std::string> I_FIELD1;
Field<const char *> I_FIELD2;
Field<std::string, hex2dec> I_FIELD3;
Field<int> I_FIELD4;
};
int main()
{
Record rec;
std::cout << rec.I_FIELD1.get() << std::endl;
std::cout << rec.I_FIELD2.get() << std::endl;
std::cout << rec.I_FIELD3.get() << std::endl;
std::cout << rec.I_FIELD4.get() << std::endl;
}