Templates with <class Comparable> in C++ - c++

I am attempting to compare algorithms. I am not familiar with the C++. I want to create a main where I will include the code below as a header. I don't completely understand what "template class Comparable" is though.
#include <vector>
using namespace std;
template <class Comparable>
void SelectionSort(vector<Comparable> & nums, int low, int high)
{
for (int i = low; i <= high-1; i++) {
int indexOfMin = i; // traverse the list to
for (int j = i+1; j <= high; j++) { // find the index of the
if (nums[j] < nums[indexOfMin]) { // next smallest item
indexOfMin = j;
}
}
Comparable temp = nums[i]; // swap the next smallest
nums[i] = nums[indexOfMin]; // item into its correct
nums[indexOfMin] = temp; // position
}
}
template <class Comparable> void SelectionSort(vector<Comparable> & nums)
{
SelectionSort(nums, 0, nums.size()-1);
}

Your main sort function there looks like this (snipping the "template" part for now):
void SelectionSort(vector<Comparable> & nums)
{
SelectionSort(nums, 0, nums.size()-1);
}
Looks like a normal sort function that acts on a vector of Comparables. But what is a Comparable? Well imagine if "Comparable" were nothing more than an alias for "int" (it's not, but imagine). Then you'd have this:
void SelectionSort(vector<int> & nums)
{
SelectionSort(nums, 0, nums.size()-1);
}
This is ordinary C++ code. It declares and defines a function that sorts a vector of ints. Pretty straightforward.
Comparable doesn't have a standard meaning like that. It is a term invented by the code in your question. It is declared by the text template <class Comparable>, approximately the way a variable is declared. It is something like a "type variable". An ordinary variable represents one of many values; a type variable represents one of many types.
template <class Comparable> void SelectionSort(vector<Comparable> & nums)
{
SelectionSort(nums, 0, nums.size()-1);
}
This code declares that Comparable is not automatically int, or float, or std::string, but rather may be any type at all. To use this function you must specify what type you want when you call the function. You can do it explicitly:
std::vector<int> someints;
SelectionSort<int>(someints);
(And this will make "Comparable" mean "int" after all, within that one call.)
Or you can leave out that extra specification and hope for the compiler to figure it out:
std::vector<int> someints;
SelectionSort(someints);
And you can use the same template for different types as much as you want; it is not "spent" in any sense by one use:
std::vector<int> someints, moreints;
std::vector<float> somefloats;
SelectionSort(someints);
SelectionSort(somefloats);
SelectionSort(moreints);
For a simple purpose like this, you can imagine that SelectionSort is a function that works on many types, not just one. But actually it is not a function. It is a whole family of potential functions, some of which may be instantiated by the compiler. The code just above calls SelectionSort three times, but with only two Comparable types, and so behind the scenes it creates two actual functions.
I've been talking about Comparable as a variable, but it can't vary WITHIN an instance of the template. You can't do Comparable=float within SelectionSort<int> or anything like that. It varies from one instance of the template to another, not within one instance. When the template is instantiated as a real function, Comparable is replaced by the type that was specified for it and then forgotten; that function doesn't "know" it is an instance of the template. It's just a function that happens to have angle brackets in its name. I think.
There are indeed some very powerful, complicated, mind-bending things that can be done with templates. But you probably don't need to know much about those for your purpose.
One more important basic point, though, is that there are also template classes. std::vector itself is one of them. They work in a roughly analogous way to template functions like SelectionSort: the header <vector> declares the vector template only once for all types, but then you can say std::vector<int> and then later std::vector<SomeClassIMade> and so on, and thereby automatically instantiate two (or more) actual classes. All these classes will work like a C++ vector is supposed to, but each one will only know how to handle its own specified element type, and will not understand any other.

Related

Passing array of vectors as a function parameter (values will not change)

I have an array of vectors in one class:
class MeasurementData
{
private:
std::vector<double> m_measuredStrengths[3];
}
And I would like a function of another class to examine that and pass back an integer based on the analysis, e.g.
int CStrengthAnalyser::GetBestFit(std::vector<double> measuredStrengths[3])
{
int bestFit = -1;
// do stuff
return bestFit;
}
And I'm a little confused by the best practice for passing this kind of object around, plus setting up my receiving function to guarantee no changes to the original data.
Is my function declaration OK as-is, or do I need to add some best practice tweaks?
The function you have right now is the same function as:
int CStrengthAnalyser::GetBestFit(std::vector<double> * measuredStrengths )
So it can definitely modify the vectors. If you're always dealing with an array of size 3 you can take a const reference to an array of size 3.
int CStrengthAnalyser::GetBestFit(std::vector<double> const (&measuredStrengths)[3])
Or if you want to make it more generic:
struct CStrengthAnalyser
{
// ...
template<std::size_t N>
int GetBestFit(std::vector<double> const (&measuredStrengths)[N])
{ ... }
};
In this case the member function definition must appear in the header (or, to be precise, the definition must be visible to the compiler at the callsite).
If you want to avoid the ugly reference to array syntax you could change the MeasurementData definition to contain a std::array<std::vector<double>, 3> instead of a plain C array. Then passing a reference to that is cleaner
int CStrengthAnalyser::GetBestFit(std::array<std::vector<double>, 3> const& measuredStrengths)
And finally, you could also deduce the size of the std::array using a function template as shown previously.
I would suggest that you use a vector of vectors here, like
vector<vector<double> > your_measure(3);
When you pass it into another function, you can use the key word const to it, like
my_fun(vector<vector<double> > const & your_vec_vec);

General iterable type with specific element type

I'm trying to write a function for enumerating through a number of a specific base, where the number is stored in some kind of list. Here is an example, taking a std::vector
void next_value(std::vector<unsigned int> &num, unsigned int base) {
unsigned int carry = 1;
for (unsigned int &n: num) {
n += carry;
if (n >= base) {
carry = 1;
n = 0;
} else {
carry = 0;
}
}
}
The num vector doesn't necessarily need to be a vector, it can be an array, or actually any type that has a std::begin() and std::end() defined for it. Is there a way to express that num can be anything with begin() and end(), but that it must have unsigned int type for its elements?
If you really want to check this, try:
template <class Sequence>
void next_value(Sequence &num, unsigned int base) {
static_assert(boost::is_same<Sequence::value_type, unsigned>::value, "foo");
// ...
If you're not using C++11 yet, use BOOST_STATIC_ASSERT instead.
If you need to support plain C-style arrays, a bit more work is needed.
On the other hand, #IgorTandetnik correctly points out that you probably do not need to explicitly check at all. The compiler will give you an (ugly) error if you pass a type which is truly unusable.
Writing a generic function with a static_assert is a good idea, because you can give the user a helpful error message rather than "foo".
However there is another approach using C++11:
template <typename Container, typename ValueType>
typename std::enable_if<std::is_same<Container::value_type, ValueType>::value, void>::type
next_value(Container& num, ValueType base)
{
// ...
}
This is a rather cryptic approach if you've never seen this before. This uses "Substitution failure is not an error" (SFINAE for short). If the ValueType doesn't match the Container::value_type, this template does not form a valid function definition and is therefore ignored. The compiler behaves as if there is not such function. I.e., the user can't use the function with an invalid combination of Container and ValueType.
Note that I do recommend using the static_assert! If you put a reasonable error message there, the user will thank you a thousand times.
I would not in your case.
Change carry to a book, use ++ instead of +=, make base a type T, and n an auto&.
Finally, return carry.
Your code now ducktypes exactly the requirements.
If you want diagnostics, static assert that the operations make sense with custom error messages.
This let's your code handle unsigned ints, polynomials, bigints, whatever.

How to iterate through variable members of a class C++

I'm currently trying to do a complicated variable correction to a bunch of variables (based on normalizing in various phase spaces) for some data that I'm reading in. Since each correction follows the same process, I was wondering if there would be anyway to do this iteratively rather than handle each variable by itself (since I need to this for about 18-20 variables). Can C++ handle this? I was told by someone to try this in python but I feel like it could be done in C++ in some way... I'm just hitting a wall!
To give you an idea, given something like:
class VariableClass{
public :
//each object of this class represents an event for this particlular data set
//containing the following variables
double x;
double y;
double z;
}
I want to do something along the lines of:
for (int i=0; i < num_variables; i++)
{
for (int j=0; j < num_events; j++)
{
//iterate through events
}
//correct variable here, then move on to next one
}
Thanks in advance for any advice!!!
I'm assuming your member variables will not all have the same type. Otherwise you can just throw them into a container. If you have C++11, one way you could solve this problem is a tuple. With some template metaprogramming you can simulate a loop over all elements of the tuple. The function std::tie will build a tuple with references to all of your members that you can "iterate" like this:
struct DoCorrection
{
template<typename T>
void operator()(T& t) const { /* code goes here */ }
};
for_each(std::tie(x, y, z), DoCorrection());
// see linked SO answer for the detailed code to make this special for_each work.
Then, you can specialize operator() for each member variable type. That will let you do the appropriate math automatically without manually keeping track of the types.
taken from glm (detail vec3.incl)
template <typename T>
GLM_FUNC_QUALIFIER typename tvec3<T>::value_type &
tvec3<T>::operator[]
(
size_type i
)
{
assert(i < this->length());
return (&x)[i];
}
this would translate to your example:
class VariableClass{
public :
//each object of this class represents an event for this particlular data
double x;
double y;
double z;
double & operator[](int i) {
assert(i < 3);
return (&x)[i];
}
}
VariableClass foo();
foo.x = 2.0;
std::cout << foo[0] << std::endl; // => 2.0
Althought i would recomment glm, if it is just about vector math.
Yes, just put all your variables into a container, like std::vector, for example.
http://en.cppreference.com/w/cpp/container/vector
I recommend spending some time reading about all the std classes. There are many containers and many uses.
In general you cannot iterate over members without relying on implementation defined things like padding or reordering of sections with different access qualifiers (literally no compiler does the later - it is allowed though).
However, you can use a the generalization of a record type: a std::tuple. Iterating a tuple isn't straight-forward but you will find plenty of code that does it. The worst here is the loss of named variables, which you can mimic with members.
If you use Boost, you can use Boost.Fusion's helper-macro BOOST_FUSION_ADAPT_STRUCT to turn a struct into a Fusion sequence and then you can use it with Fusion algorithms.

C++ check if element is std::vector

i would like to iterate through a vector and check if elements are vectors or strings. Also i need a way to pass different vecors to a function.
Something like this:
using namespace std;
string toCustomString(<some vector> vec) {
string ret = "";
for(size_t i = 0; i < vec.length(); ++i)
if (vec[i] == %vector%)
ret += toCustomString(vec[i]);
else //if type of vec[i] is string
ret += "foo"+vec[i]+"bar";
}
return ret;
}
Well, first i need to know how i can check correctly if vec[i] is a std::vector
Then i need to know how to define the paramater for the function to accept any kind of (multidimensional) vector
std::vector can only contain one type - that is the T in std::vector<T>, which can be accessed with the member value_type.
What you probably are looking for is template specialization:
template<typename T>
string toCustomString(std::vector<T> vec) {
// general case
}
template<>
string toCustomString<std::string>(std::vector<std::string> vec) {
// strings
}
(if you want to partially specialize it over all vectors then you'll need to lift it to a struct)
If you really want to store both strings and vectors in the vector then look at Boost.Variant and Boost.Any
Generally, your <some vector> vec would have type either vector<string> or vector<vector<string>>, for example.
In order to declare the variable, you need its type, and its type also specifies exactly what it stores.
Now, you can work around this using Boost.Variant (or roll your own discriminated union), like so:
typedef boost::variant<std::string, std::vector<std::string>> Vec_of_StringOrVec;
but Dirk Holsopple is right that this isn't idiomatic C++, and you may be better off looking for a different approach.
As everyone says, vectors in C++ only hold one type. There's no need or point in checking the type of each element in turn, which is just as well because there's no way to do that. What you do instead is overload the function on the type of the argument. Something like this:
string toCustomString(const string &str) {
return "foo" +str + "bar";
}
template <typename T>
string toCustomString(const std::vector<T> &vec) {
string ret;
for(size_t i = 0; i < vec.size(); ++i)
ret += toCustomString(vec[i]);
return ret;
}
Now, if someone passes a vector<string> into toCustomString then the call toCustomString(vec[i]) will select the toCustomString(const string &str) overload.
If someone passes a vector<int> into toCustomString then the code won't compile, because there is (currently) no toCustomString(int) overload[*].
If someone passes a vector<vector<string>> to toCustomString then toCustomString(vec[i]) will pass a vector<string>, see above.
In all three cases, different toCustomString functions are called. In the first case it's toCustomString<string>(const vector<string>&), which is a different instantiation of the toCustomString template from the third case, toCustomString<vector<string>>(const vector<vector<string>>&). The middle case tries to instantiate toCustomString<int>, but fails because toCustomString(v[i]) doesn't match any function it knows about.
All of this is determined at compile time. The point of templates is to create multiple functions (or classes) with particular differences between them. In this case the difference is the type of vector passed in.
[*] This seems in line with your claim that vec[i] must be either a vector or a string, not any third option. If you wanted for example the return value for a vector<something_else> to be empty, then you could add a catch-all template:
template <typename T>
string toCustomString(const T &) {
return string();
}
and of course you can add more overloads for any other types you want to handle.

C++ cast to array of a smaller size

Here's an interesting question about the various quirks of the C++ language. I have a pair of functions, which are supposed to fill an array of points with the corners of a rectangle. There are two overloads for it: one takes a Point[5], the other takes a Point[4]. The 5-point version refers to a closed polygon, whereas the 4-point version is when you just want the 4 corners, period.
Obviously there's some duplication of work here, so I'd like to be able to use the 4-point version to populate the first 4 points of the 5-point version, so I'm not duplicating that code. (Not that it's much to duplicate, but I have terrible allergic reactions whenever I copy and paste code, and I'd like to avoid that.)
The thing is, C++ doesn't seem to care for the idea of converting a T[m] to a T[n] where n < m. static_cast seems to think the types are incompatible for some reason. reinterpret_cast handles it fine, of course, but is a dangerous animal that, as a general rule, is better to avoid if at all possible.
So my question is: is there a type-safe way of casting an array of one size to an array of a smaller size where the array type is the same?
[Edit] Code, yes. I should have mentioned that the parameter is actually a reference to an array, not simply a pointer, so the compiler is aware of the type difference.
void RectToPointArray(const degRect& rect, degPoint(&points)[4])
{
points[0].lat = rect.nw.lat; points[0].lon = rect.nw.lon;
points[1].lat = rect.nw.lat; points[1].lon = rect.se.lon;
points[2].lat = rect.se.lat; points[2].lon = rect.se.lon;
points[3].lat = rect.se.lat; points[3].lon = rect.nw.lon;
}
void RectToPointArray(const degRect& rect, degPoint(&points)[5])
{
// I would like to use a more type-safe check here if possible:
RectToPointArray(rect, reinterpret_cast<degPoint(&)[4]> (points));
points[4].lat = rect.nw.lat; points[4].lon = rect.nw.lon;
}
[Edit2] The point of passing an array-by-reference is so that we can be at least vaguely sure that the caller is passing in a correct "out parameter".
I don't think it's a good idea to do this by overloading. The name of the function doesn't tell the caller whether it's going to fill an open array or not. And what if the caller has only a pointer and wants to fill coordinates (let's say he wants to fill multiple rectangles to be part of a bigger array at different offsets)?
I would do this by two functions, and let them take pointers. The size isn't part of the pointer's type
void fillOpenRect(degRect const& rect, degPoint *p) {
...
}
void fillClosedRect(degRect const& rect, degPoint *p) {
fillOpenRect(rect, p); p[4] = p[0];
}
I don't see what's wrong with this. Your reinterpret-cast should work fine in practice (i don't see what could go wrong - both alignment and representation will be correct, so the merely formal undefinedness won't carry out to reality here, i think), but as i said above i think there's no good reason to make these functions take the arrays by reference.
If you want to do it generically, you can write it by output iterators
template<typename OutputIterator>
OutputIterator fillOpenRect(degRect const& rect, OutputIterator out) {
typedef typename iterator_traits<OutputIterator>::value_type value_type;
value_type pt[] = {
{ rect.nw.lat, rect.nw.lon },
{ rect.nw.lat, rect.se.lon },
{ rect.se.lat, rect.se.lon },
{ rect.se.lat, rect.nw.lon }
};
for(int i = 0; i < 4; i++)
*out++ = pt[i];
return out;
}
template<typename OutputIterator>
OutputIterator fillClosedRect(degRect const& rect, OutputIterator out) {
typedef typename iterator_traits<OutputIterator>::value_type value_type;
out = fillOpenRect(rect, out);
value_type p1 = { rect.nw.lat, rect.nw.lon };
*out++ = p1;
return out;
}
You can then use it with vectors and also with arrays, whatever you prefer most.
std::vector<degPoint> points;
fillClosedRect(someRect, std::back_inserter(points));
degPoint points[5];
fillClosedRect(someRect, points);
If you want to write safer code, you can use the vector way with back-inserters, and if you work with lower level code, you can use a pointer as output iterator.
I would use std::vector or (this is really bad and should not be used) in some extreme cases you can even use plain arrays via pointer like Point* and then you shouldn't have such "casting" troubles.
Why don't you just pass a standard pointer, instead of a sized one, like this
void RectToPointArray(const degRect& rect, degPoint * points ) ;
I don't think your framing/thinking of the problem is correct. You don't generally need to concretely type an object that has 4 vertices vs an object that has 5.
But if you MUST type it, then you can use structs to concretely define the types instead.
struct Coord
{
float lat, long ;
} ;
Then
struct Rectangle
{
Coord points[ 4 ] ;
} ;
struct Pentagon
{
Coord points[ 5 ] ;
} ;
Then,
// 4 pt version
void RectToPointArray(const degRect& rect, const Rectangle& rectangle ) ;
// 5 pt version
void RectToPointArray(const degRect& rect, const Pentagon& pent ) ;
I think this solution is a bit extreme however, and a std::vector<Coord> that you check its size (to be either 4 or 5) as expected with asserts, would do just fine.
I guess you could use function template specialization, like this (simplified example where first argument was ignored and function name was replaced by f(), etc.):
#include <iostream>
using namespace std;
class X
{
};
template<int sz, int n>
int f(X (&x)[sz])
{
cout<<"process "<<n<<" entries in a "<<sz<<"-dimensional array"<<endl;
int partial_result=f<sz,n-1>(x);
cout<<"process last entry..."<<endl;
return n;
}
//template specialization for sz=5 and n=4 (number of entries to process)
template<>
int f<5,4>(X (&x)[5])
{
cout<<"process only the first "<<4<<" entries here..."<<endl;
return 4;
}
int main(void)
{
X u[5];
int res=f<5,5>(u);
return 0;
}
Of course you would have to take care of other (potentially dangerous) special cases like n={0,1,2,3} and you're probably better off using unsigned int's instead of ints.
So my question is: is there a
type-safe way of casting an array of
one size to an array of a smaller size
where the array type is the same?
No. I don't think the language allows you to do this at all: consider casting int[10] to int[5]. You can always get a pointer to it, however, but we can't 'trick' the compiler into thinking a fixed-sized has a different number of dimensions.
If you're not going to use std::vector or some other container which can properly identify the number of points inside at runtime and do this all conveniently in one function instead of two function overloads which get called based on the number of elements, rather than trying to do crazy casts, consider this at least as an improvement:
void RectToPointArray(const degRect& rect, degPoint* points, unsigned int size);
If you're set on working with arrays, you can still define a generic function like this:
template <class T, size_t N>
std::size_t array_size(const T(&/*array*/)[N])
{
return N;
}
... and use that when calling RectToPointArray to pass the argument for 'size'. Then you have a size you can determine at runtime and it's easy enough to work with size - 1, or more appropriate for this case, just put a simple if statement to check if there are 5 elements or 4.
Later if you change your mind and use std::vector, Boost.Array, etc. you can still use this same old function without modifying it. It only requires that the data is contiguous and mutable. You can get fancy with this and apply very generic solutions that, say, only require forward iterators. Yet I don't think this problem is complicated enough to warrant such a solution: it'd be like using a cannon to kill a fly; fly swatter is okay.
If you're really set on the solution you have, then it's easy enough to do this:
template <size_t N>
void RectToPointArray(const degRect& rect, degPoint(&points)[N])
{
assert(N >= 4 && "points requires at least 4 elements!");
points[0].lat = rect.nw.lat; points[0].lon = rect.nw.lon;
points[1].lat = rect.nw.lat; points[1].lon = rect.se.lon;
points[2].lat = rect.se.lat; points[2].lon = rect.se.lon;
points[3].lat = rect.se.lat; points[3].lon = rect.nw.lon;
if (N >= 5)
points[4].lat = rect.nw.lat; points[4].lon = rect.nw.lon;
}
Yeah, there is one unnecessary runtime check but trying to do it at compile time is probably analogous to taking things out of your glove compartment in an attempt to increase your car's fuel efficiency. With N being a compile-time constant expression, the compiler is likely to recognize that the condition is always false when N < 5 and just eliminate that whole section of code.