Sign in to follow this  
jmau0438

Function as Template parameter using boost

Recommended Posts

What up game dev!? Man, I'm stuck again. I guess I'd better explain what I'm doing and what I'd like to do. I have a template function that returns the absolute value of a variable via the fabs. Its pretty common knowledge that fabs only handles floating point values (float & double). What about about integers? Well, then you use abs. My goal with this function is to have fabs as the default function, but allow for it to be replaced with abs. I suppose I could use a function pointer, but I sure would like to see it inside the template argument list. Additionally, every time I use boost, I find a simpiler alternative derived from the STL that works just as good. I know boost is a powerful library, I just want to see it for myself. I've been using boost for a little while, so I did my homework to see if boost might have anything that might work. I found a site that gave me some hope, http://bytes.com/topic/c/answers/138989-class-template-parameter-function, so I chewed on this bone for a while. It appears that in the boost library their is a .hhp file called functionality that has a templated structure called unary_traits ( see http://www.boost.org/doc/libs/1_40_0/libs/functional/function_traits.html and http://www.boost.org/doc/libs/1_40_0/boost/functional.hpp for details ) that handles this. So I gave it a try, and I just can't make it work. More likely I just don't know how to use it. My fear is that this only works for member functions and if so I'm SOL, cause I'm just using a function call in a namespace. Here is the function prior to my boost alterations:
template < typename TYPE >  
inline TYPE AbsoluteDeviation ( std :: vector < TYPE > &Vec, const int Index, const bool &isSorted = false ) {

     //Compute and return the difference of the mean and indexed value
     return std :: fabs ( Vec [ Index ] - Median < TYPE > ( Vec, isSorted ) );

};






If you can, please throw this dog a bone. Thanks everybody.

Share this post


Link to post
Share on other sites
What's wrong with overloading, here?

int my_abs(int x) { return std::abs(x); }
double my_abs(double x) { return std::fabs(x); }

/* Note: pass vec as const reference, since you're not changing it;
* equally, don't pass integral types by reference - especially when you have to
* jump through unnecessary hoops to bind temporaries to it!
*/
template <typename T> T AbsoluteDeviation(const std::vector<T>& vec, int index, bool sorted = false)
{
return static_cast<T>(my_abs(vec[index] - median(vec, sorted)));
}


Add a floating point overload if you like and avoid the static_cast. I'm not too sure if I understood you correctly though, so this might not be what you're looking for.

Share this post


Link to post
Share on other sites
Yea, overloading occurred to me to, and if I can't figure this out I'm either going to overload or include a function pointer in the argument list. I'm really just trying to do something interesting with boost. O yea, the reason I don't have a constant cast on the vector argument is that the Median function actually sorts the values stored in the vector. I'm pretty sure if I added the const cast it would mess that up. Am I wrong?

Share this post


Link to post
Share on other sites
Er, I was being stupid, sorry. std::abs is already overloaded for float and double. You don't need to do anything clever at all. D'oh!

Since you're interested in Boost, and mention function pointers, you might be interested in Boost.Function (recently standardized as std::tr1::function and friends). Also, unary_traits wouldn't really have helped here in any case - it's for getting details about the types involved in a function (the function type itself, and the type of its argument and return value).

Share this post


Link to post
Share on other sites
O wow, so you understand how to use the unary_traits? Man, it may not be what I need but i've looked into this thing way to hard to not understand it. Could you break this thing down for me in a way I'll understand. Just remember, I'm actually a total idiot, so I hope your fluent in dummy.

So your saying what I'm looking for is in std::tr1::function? Isn't that the filler type function call that you can throw into a template parameter list instead of writing your own? I've done this, but I've never used it to reference a function. Dude, am I even close in my understanding here or am I totally lost?

Share this post


Link to post
Share on other sites
Quote:
Original post by jmau0438
O wow, so you understand how to use the unary_traits? Man, it may not be what I need but i've looked into this thing way to hard to not understand it. Could you break this thing down for me in a way I'll understand. Just remember, I'm actually a total idiot, so I hope your fluent in dummy.

So your saying what I'm looking for is in std::tr1::function? Isn't that the filler type function call that you can throw into a template parameter list instead of writing your own? I've done this, but I've never used it to reference a function. Dude, am I even close in my understanding here or am I totally lost?


There's a reasonable amount I'm assuming here, not to mention making a mistake to begin with, so don't worry if you didn't think I was very clear!

You have functions, which you're used to dealing with, but you can also have function objects - classes (or structs[1]) which are designed to act a bit like functions. For example, consider:

// A class that acts like a function that adds a certain amount
class Incrementer
{
int increment;

public:
Incrementer(int increment)
: increment(increment) // [2]
{}

void operator()(int& x) { x += increment; }
};


Now we can get a function object (just an instance of this class) that acts almost like a function that increments by the value that was specified when the object was constructed:

void someOtherFunction()
{
Incrementer inc(2);

int x = 5;
inc(x); // Almost like a function call; x is now 7, as you would expect
inc(x); // ... and x is 9
}


In this particular case, it's not an awfully useful thing. However, in general, it's a very useful ability because it allows us to treat functions (or, rather, function objects that look like functions) as if they were 'first-class citizens' in the language.

A first-class citizen is an object in the language that can be treated no differently from most other objects - for example, integers are first-class in C++. You can pass integers as arguments, store them in variables, create them at runtime, and so on. You can't really do this with functions in C++ - function pointers go a little way towards resolving some of these issues, but they're not quite 'there'. As a terminology thing, you might hear of 'functional' programming languages: amongst other idiosyncracies, allowing functions to be first-class entities is one of their defining features.

As a couple concrete examples of why using functions in this way is helpful, first consider the generic 'callback' mechanism whereby you want to specify a function to be called when something happens (usually when some process is completed or an external event occurs) - a button might have a callback that it invokes when it's clicked. This can be used to add extra abstraction to common tasks. Think about what you're looking to do is 'do this thing to every item in this collection' - this is a task generalized in some libraries to a single function called 'map' which takes a function (or function object) as an argument, as well as the collection involved.

Boost.Function (which is what I'm going to call it, despite it being standardized since then, sorry!) primarily addresses one particular problem: allowing function pointers and function objects to be handled through a single interface. That is to say, if I have something like this:

// Abstract base class - function objects can inherit from this
template <typename ResultT, ParamT> struct UnaryFunction
{
virtual ResultT operator()(ParamT param) = 0;
};


then I can have a function accept a pointer/reference to a UnaryFunction function object as a parameter. However, there's no easy way for that function to accept a function pointer in its stead. Boost.Function does the legwork to allow both types to be stored in a single variable. For more information, see the Boost documentation (which includes a tutorial, of which you might find the Basic Usage section of most use).

unary_traits is a class which, through template magic, allows you to reconstruct the types involved in a function which you were passed as a parameter, if you don't already know them (which is possible if your function is also templated). However, I've never actually used it, so this is just what I'm gleaning from the documentation.

[1] Classes and structs are the same thing, with a minor difference. Classes default to 'private' access whilst structs default to 'public' access.

[2] If you haven't seen this, it's called an initializer list. You can think of it almost as if I was doing this->increment = increment inside the constructor, but with an important difference. If I did that, then the member increment (the one that's part of the class, not the argument passed in) would first be default-initialized (to 0) and then assigned the value I want it. This isn't really what we want to do, is inefficient and (for more complicated things) can either introduce bugs or be flat-out impossible (for classes that don't have a default constructor). Instead, we use the initializer list, which avoids the default-initialization.

Note: there's a fair bit I've glossed over here, but I hope this is enough to let you read the documentation and do some Googling to understand better. Equally, this could either be too high or too low a level - I'm not sure how much you do know, so I've just done a sort of braindump!


******

To answer your actual question: I'm not saying that you need Boost at all in this case. I'm saying that you can just use abs and ignore fabs entirely. In C++ (rather than C), abs works for floating point types as well as for integer types, because C++ has function overloading and C does not. You don't need to do any work at all, your function can just look like this:

template < typename TYPE >  
inline TYPE AbsoluteDeviation ( std :: vector < TYPE > &Vec, const int Index, const bool &isSorted = false ) {

//Compute and return the difference of the mean and indexed value
return std :: abs ( Vec [ Index ] - Median < TYPE > ( Vec, isSorted ) );

};


(Note use of std::abs rather than std::fabs.)

Share this post


Link to post
Share on other sites
So I was correct in my assumption that this only worked for classes & structures. I understand what you mean by first-class citizen types. Actionscript makes a bunch of objects and even function calls first class through the keywords of the language, so I understand. Member access restrictions don't surprise me. It seems there just preserving the standard defaults (class - PRIVATE, struct - PUBLIC) in their implementation.

So, all my effort trying to make it work for int was already there. Man, I must look quite the fool. But thanks for helping me understand the "function_traits" better. There is another side to this coin where I belive I can still apply this. I'll post when I have something, either today or tommorrow. Thanks again man.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this