I am making some template numerical array classes that make it easy to do mathematical operations. For instance, you could do something like the following to go from linear values to dB:
buf = 10 * buf.log10();
I would like to change methods like "log10" to non-member template functions that take a DspBuffer reference as an argument. Aesthetically I think that would be a lot nicer because then the previous code would look like this:
buf = 10 * log10(buf);
The only problem with this approach is that some classes inherit from DspBuffer, like FixedPtDspBuffer (when using fixed point data types) and ComplexDspBuffer (for complex values). I sometimes need to overload the functions, and I'm not sure that I can do that with non-member template functions. For instance, with log10() and fixed point I would like to round the result of the underlying log10 result instead of implicitly doing a "floor" when converting back to fixed point.
Can I overload non-member template functions by making them more specific (i.e. one takes a DspBuffer, and one takes a FixedPtDspBuffer that inherits from DspBuffer), or is this doomed to failure?
You can certainly provide overloads to free functions such as your log10 that respectively take a DspBuffer& or a FixedPtDspBuffer, etc. However unless your local code knows that it's working on the subclass, templates or not, those overloads won't be invoked. So the free function near equivalent of a virtual method call will always call the chosen base class overload.
One approach to get the virtual-style dispatch back would be to implement a virtual method on the object that the free function calls. If desirable, you could mark the method protected or private and the function a friend. Python does this sort of thing a lot, actually, with free function calls like len(obj) that in turn call obj.__length__().
(I think this is architecturally similar to the Visitor pattern that Jarod42 suggested, but it doesn't hold itself to the names accept and visit.)
Related
Why are functions of objects generally defined as class member functions instead of friend functions (with the associated instantiated object passed in as a parameter)?
If you implement push_back(vector v, val), front(vector v), back(vector) as friend functions that take as a parameter a vector, for example, would that not save on space, because the functions would not have to be defined each time a vector object is created, but only once?
I'm sorry if my question doesn't make much sense. I'm new to coding and I am not completely comfortable with its jargon/terminology. If I need to reword my question because it is unclear, please let me know.
Thank you :)
Unless they’re virtual, member functions don’t take up any space inside a class. And virtual member functions only take up constant space. This is usually 8 bytes, independent of how many virtual functions the class has. This is because classes with virtual functions contain a pointer to a vtable which looks up the actual function at runtime.
That being said, having friend functions at namespace scope is useful because it allows you to make overload sets. An overload set is just the name for all the overloads of a particular function name. For example, std::to_string is an overload set because there are multiple functions with that name.
Overload sets are a really useful concept because they allow you to write generic code that can act on a lot of different types, even if those types are completely unrelated For example, std::vector and std::list don’t inherit from each other or from a base class, but it’s easy to write templated functions that work on either of them because they share a common interface in terms of how they can be used.
If you implement push_back(vector v, val), front(vector v), back(vector) as friend functions that take as a parameter a vector, for example, would that not save on space, because the functions would not have to be defined each time a vector object is created, but only once?
Functions are not "defined each time a vector object is created". You don't save space by using friend functions as such.
The advantages of member functions mostly revolve around inheritance. Member functions can have protected access, and they can be virtual etc.
Friend functions are useful in implementing symmetric binary (i.e. two-argument, counting this) functions. As a member function the first argument would be special and cannot be treated equally. Furthermore, friend functions can provide an API compatible with C, which is useful for cross-language programming and shared libraries.
I'm trying to make a menu array where each element is a struct that stores variables for text, key that needs to be pressed to select that item and function called on that key press (something like "Quit", 'Q', Quit()). I thought this would make things more efficient, but I can't find a way to make it work with varied function and parameter types (for example one item should be able to call a void function with no parameters, another a class int function with two parameters and so on). Is there a good way to do this or am I better off giving up on the idea?
Edit: Thank you all for your advice! The proposed solutions feel a little too complex for my newbie self, but attempting to understand them gave me some ideas! I ended up making the third variable hold an enum instead of a direct function call and then created a switch function that calls other functions based on that value.
There are actually a few ways of doing this.
One way is to use std::bind to bind all functions to void func(void) then you can store them equally.
The other way is to create a generic function/lambda which will call your function.
To store your functions you can use std::function.
Also consider overriding operator() of your classes.
The classic way of handling this is to have all the functions take the same parameters, and for those to be very flexible. For example, an integer or enum, and a pointer.
your no-parameter function is passed -1 and nullptr and ignores them
your multi-parameter function casts the pointer to a pointer to some struct or class that holds all the bits and pieces it needs (and of course your calling code made that instance and passed its address)
The reason an enum or integer is hoisted out as one of the parameters is that "command type" is a super popular thing to need, so why do all that casting and extracting to get it?
If you have a performance problem as a result of this approach, then there are others, but this has literally been used for decades in Windows.
Why are those C++11 new functions of header <string> (stod, stof, stoull) not member functions of the string class ?
Isn't more C++ compliant to write mystring.stod(...) rather than stod(mystring,...)?
It is a surprise to many, but C++ is not an Object-Oriented language (unlike Java or C#).
C++ is a multi-paradigm language, and therefore tries to use the best tool for the job whenever possible. In this instance, a free-function is the right tool.
Guideline: Prefer non-member non-friend functions to member functions (from Efficient C++, Item 23)
Reason: a member function or friend function has access to the class internals whereas a non-member non-friend function does not; therefore using a non-member non-friend function increases encapsulation.
Exception: when a member function or friend function provides a significant advantage (such as performance), then it is worth considering despite the extra coupling. For example even though std::find works really well, associative containers such as std::set provide a member-function std::set::find which works in O(log N) instead of O(N).
The fundamental reason is that they don't belong there. They
don't really have anything to do with strings. Stop and think
about it. User defined types should follow the same rules as
built-in types, so every time you defined a new user type,
you'd have to add a function to std::string. This would
actually be possible in C++: if std::string had a member
function template to, without a generic implementation, you
could add a specialization for each type, and call
str.to<double>() or str.to<MyType>(). But is this really
what you want. It doesn't seem like a clean solution to me,
having everyone writing a new class having to add
a specialization to std::string. Putting these sort of things
in the string class bastardizes it, and is really the opposite
of what OO tries to achieve.
If you were to insist on pure OO, they would have to be
members of double, int, etc. (A constructor, really. This
is what Python does, for example.) C++ doesn't insist on pure
OO, and doesn't allow basic types like double and int to
have members or special constructors. So free functions are
both an acceptable solution, and the only clean solution
possible in the context of the language.
FWIW: conversions to/from textual representation is always
a delicate problem: if I do it in the target type, then I've
introduced a dependency on the various sources and sinks of text
in the target type---and these can vary in time. If I do it in
the source or sink type, I make them dependent on the the type
being converted, which is even worse. The C++ solution is to
define a protocol (in std::streambuf), where the user writes
a new free function (operator<< and operator>>) to handle
the conversions, and counts on operator overload resolution to
find the correct function. The advantage of the free function
solution is that the conversions are part of neither the data
type (which thus doesn't have to know of sources and sinks) nor
the source or sink type (which thus doesn't have to know about
user defined data types). It seems like the best solution to
me. And functions like stod are just convenience functions,
which make one particularly frequent use easier to write.
Actually they are some utility functions and they don't need to be inside the main class. Similar utility functions such as atoi, atof are defined (but for char*) inside stdlib.h and they too are standalone functions.
Are function pointers functors ? Is there a virtual functor in use that helps sibling functors compile silently ?
At least as the term is normally used in C++ (Warning: it's used entirely differently relative to other languages such as Haskell), a functor is a class (or an instance of a class) that overloads operator() so it can be invoked like a function.
Since they use the same syntax, a template can be written to accept either a pointer to a function or an instance of a functor interchangeably. Not all algorithms will do so however -- some expect (for example) that you supply something with typedefs for things like argument_type and result_type. The standard library provides a couple of classes (unary_function and binary_function) to use as base classes for your functors to supply these. You can supply them on your own if you prefer -- these base classes are purely for convenience (and some people don't find them particularly convenient).
A function pointer is the address of a real function. A functor is a class for which the operator() has been overloaded; instances of these classes can be passed around and called with the same syntax as a function. So no, function pointers are not functors.
I don't know what "virtual functors" or "sibling functors" are, so I can't answer your second question.
I'm using C++ templates to pass in Strategy functors to change my function's behavior. It works fine. The functor I pass is a stateless class with no storage and it just overloads the () operator in the classic functor way.
template <typename Operation> int foo(int a)
{
int b=Operation()(a);
/* use b here, etc */
}
I do this often, and it works well, and often I'm making templates with 6 or 7 templated functors passed in!
However I worry both about code elegance and also efficiency. The functor is stateless so I assume the Operation() constructor is free and the evaluation of the functor is just as efficient as an inlined function, but like all C++ programmers I always have some nagging doubt.
My second question is whether I could use an alternate functor approach.. one that does not override the () operator, but does everything in the constructor as a side effect!
Something like:
struct Operation {
Operation(int a, int &b) { b=a*a; }
};
template <typename Operation> int foo(int a)
{
int b;
Operation(a,b);
/* use b here, etc */
}
I've never seen anyone use a constructor as the "work" of a functor, but it seems like it should work. Is there any advantage? Any disadvantage? I do like the removal of the strange doubled parenthesis "Operator()(a)" , but that's likely just aesthetic.
Any disadvantage?
Ctors do not return any useful value -- cannot be used in chained calls (e.g. foo(bar()).
They can throw.
Design point of view -- ctors are object creation functions, not really meant to be workhorses.
Compilers actually inline the empty constructor of Operation (at least gcc in similar situations does, except when you turned off optimization)
The disadvantage of doing everything in the constructor is that you cannot create a functor with some internal state this way - eg. functor for counting the number of elements satisfying a predicate. Also, using a method of a real object as a functor allows you to store the instance of it for later execution, something you cannot do with your constructor approach.
From a performance pov the code demonstrated with get completely optimized with both VC and GCC. However, a better strategy often is to take the functor as a parameter, that way you get a lot more flexibility and identical performance characteristics.
I'd recommend defining functor that work with the STL-containers, i.e. they should implement operator(). (Following the API of the language you're using is always a good idea.)
That allow your algorithms to be very generic (pass in functions, functors, stl-bind, boost::function, boost::bind, boost::lambda, ...) which is what one usually wants.
This way, you don't need to specify the functor type as a template parameter, just construct an instance and pass it in:
my_algorithm(foo, bar, MyOperation())
There does not seem any point in implementing the constructor in another class.
All you are doing is breaking encapsulation and setting up your class for abuse.
The constructor is supposed to initialize the object into a good state as defined by the class. You are allowing another object to initialize your class. What guarantees do you have that this template class knows how to initialize your class correctly? A user of your class can provide any object that could mess with the internal state of your object in ways not intended.
The class should be self contained and initialize itself to a good state. What you seem to be doing is playing with templates just to see what they can do.