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.
Related
I have to write a simple code that takes a char as input or a string with an integer. Then makes a std vector, depending on the input. If the text says int I have an int vector.
The only problem is that I don't want to declare for each variable type a vector even if empty, and I want to make it scalable so if someday I want to put a struct or something else in it i can.
dvec::dvec( char t){
if ( t=='i')
vector<int> a;
else if( t=='f')
vector<float> a;
}
If all you want is primitive types or pointers, you can make a union (8 bytes in size) and a vector of that union. It's a bit C'ish, but template is a compile time solution, so for a linkable solution, you need space for every type. You can have getters, setters, constructors for each type.
You can implement this thing in two ways:
1.
using element_type = std::variant<char, int, float /* ... other types */>;
using dvec = std::vector<element_type>;
This will be type safe, albeit the disadvantage is that every element of the vector is a variant, which might not be what you want.
2.
using dvec = std::variant<std::vector<char>,
std::vector<int>,
std::vector<float> /* ... other vector types */>;
This will give you a variant of vectors, where all vector elements are homogeneous.
This cumbersome expression could be simplified by using Boost.Mp11
template<class T> using vectorize_t = std::vector<T>;
template<typename ...T>
using dvec = std::variant<mp_transform<vectorize_t, T...>>;
which basically puts all respective types in T... to an std::vector.
Write a helper function to do the real work.
template <typename T>
void do_work() {
std::vector<T> a;
// do stuff
}
// ...
if(t == 'i') {
do_work<int>();
}
else if(t == 'f') {
do_work<float>();
}
else if(t == 's') {
do_work<your_struct>();
}
Depending on what your specific uses are you might need (or at least want) to have do_work just call multiple functions, that way you can specialize if needed.
I need to find the most frequent element in an array of custom structs. There is no custom ID to them just matching properties.
I was thinking of sorting my vector by frequency but I have no clue how to do that.
I'm assuming by frequency you mean the number of times an identical structure appears in the array.
You probably want to make a hash function (or overload std::hash<> for your type) for your custom struct. Then iterate over your array, incrementing the value on an unordered_map<mytype, int> for every struct in the array. This will give you the frequency in the value field. Something like the below would work:
std::array<mytype> elements;
std::unordered_map<mytype, int> freq;
mytype most_frequent;
int max_frequency = 0;
for (const mytype &el : elements) {
freq[el]++;
if (freq[el] > max_frequency) {
most_frequent = el;
}
}
For this to work, the map will need to be able to create a hash for the above function. By default, it tries to use std::hash<>. You are expressly allowed by the standard to specialize this template in the standard namespace for your own types. You could do this as follows:
struct mytype {
std::string name;
double value;
};
namespace std {
template <> struct hash<mytype> {
size_t operator()(const mytype &t) const noexcept {
// Use standard library hash implementations of member variable types
return hash<string>()(t.name) ^ hash<double>()(t.value)
}
}
}
The primary goal is to ensure that any two variables that do not contain exactly the same values will generate a different hash. The above XORs the results of the standard library's hash function for each type together, which according to Mark Nelson is probably as good as the individual hashing algorithms XOR'd together. An alternative algorithm suggested by cppreference's hash reference is the Fowler-Noll-Vo hash function.
Look at std::sort and the example provided in the ref, where you actually pass your own comparator to do the trick you want (in your case, use the frequencies). Of course, a lambda function can be used too, if you wish.
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.
I have a function like this:
typedef std::vector<std::map<int,std::string>> MyVec1;
typedef std::vector<std::map<std::string,std::string>> MyVec2;
enum options { DEFAULT_OPTIONS = 0x0000000u,
OTHERS = 0x0000001u };
void func(std::string s1, MyVec1& vec1, MyVec2& vec2, bool type,
std::string s2, options opt, uint32_t opt2){
//do something
//And put data to the vectors
}
I want to create a luncher which can take any number of arguments (upto 7) and set default values for the arguments that are not passed and then call the func() with all arguments, kinda like this:
void launcher(args...){
//If any string is passed, pass it as the 1st arg of func, or an empty string
//If any second string is passed, pass it as the 5th arg of func or an empty string
//If any MyVec1 type is passed, pass it as the second arg or a dummy vector.
//If any MyVec2 type is passed, pass it as the third arg or a dummy vector.
////By dummy vector I mean create a vector with MyVec1 vec; and pass it as arg.
////Like this, if other args are passed they are passed to the func with
////given value otherwise a default value is chosen
////And finally call func() with all arguments.
}
The same can be achieved by overloading and using default values for arguments but that's a huge task if you consider that I want those arguments to be non-sequential too (specially the vectors) i.e launcher will manage if you pass MyVec2 first and MyVec1 as the second.
I had to create 16 overload for a three vector function (3-vector: 6, 2-vector: 6, 1-vector: 3, 0-vector: 1).
Is this even possible?
Note:
I think I can detect the type with this. But the rest seems kinda impossible to me.
If it is not possible to work with reference then that will do too. I have other functions that needs the same which doesn't work with references (A function with lots of args like the above without those vectors).
A naive implementation of what you suggested is actually fairly straightforward - you basically need something that gets the Ith T out of a tuple, or some default value if it doesn't exist. Add some forwarding pixie dust and you are done.
But it's going to be hard to maintain, and there are thorny design issues with arguments that require a conversion. "foo" by C++'s overload resolution rules converts better to bool than to std::string. Do you want to follow those rules or design your own?
Instead, do something like the named parameters idiom:
struct launcher {
std::string s1 = "";
MyVec1* p_vec1 = nullptr;
MyVec2* p_vec2 = nullptr;
bool type = false;
std::string s2 = "";
options opt = DEFAULT_OPTIONS;
uint32_t opt2 = 0;
launcher& set_s1(std::string& s) { s1 = s; return *this; }
launcher& set_vec1(MyVec1& vec1) { p_vec1 = &vec1; return *this; }
// etc.
void launch(){
MyVec1 vec1; MyVec2 vec2;
MyVec1& v1 = p_vec1 ? *p_vec1 : vec1;
MyVec2& v2 = p_vec2 ? *p_vec2 : vec2;
return func(s1, v1, v2, type, s2, opt, opt2);
}
};
I assume your intention behind launcher is to deliver a more useable interface to func. Based on this, I wouldn't rely just one a bunch of overloads or templates. You could push a little work to the runtime, but simplify the interface a lot by using simple built in pointers.
void launcher(std::string* s1, MyVec1* vec1, MyVec2* vec2, bool* type,
std::string* s2, options* opt, uint32_t* opt2){
//is s1 set?
if (s1 != nullptr) // if(s1) would also be ok
/* Construct the default parameters based on what you get*/
/* not enough parameters to call func?*/
throw std::invalid_argument("You need to specify at least ...");
You could also replace the built-in pointers with boost::optional, since it's more clear what your intentions are and boost also makes some optimizing.
You could mix this runtime checks, with overloading and templates, but I guess, launcher will not be called in a loop for scientific calculations, isn't it? And your goal is a simple interface.
I am writing my own vector class, Vector, with the data members: T* array, size_t vector_size and size_t capacity. I am trying to create a sort() method:
template <class T>
void Vector<T>::sort(bool ascending)
{
std::sort(array,array+vector_size);
if(ascending==false)
std::reverse(array,array+vector_size);
}
It works fine when the elements in the array are of type int, char etc. But when I try to sort a vector consisting of Vector elements it won't compile.
From what I have read I need to define the <operator in some way, but I really don't know how to do that...
I have tried:
template <class T>
bool Vector<T>::operator<(Vector<T> & source) const
{
return (vector_size < source.vector_size);
}
My main look like this:
int main() {
Vector<int> v1(5,1);
Vector<int> v2(7,2);
Vector<int> v3(3,3);
Vector<Vector<int>> v4;
v4 = {v1,v2,v3};
v4.sort(1);
return 0;
}
This is one of the errors I get:
/usr/include/c++/4.6/bits/stl_algo.h:2212:4: error: no match for ‘operator<’ in ‘* __first < __pivot’
You provided a comparison method with the wrong signature. You need to accept a const reference or a value, but not a (modifiable) reference to your type, while the former should be preferred unless it's a primitive type. So the signature of your comparison method should look like this:
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const
{
return (vector_size < source.vector_size);
}
This is because std::sort (and a lot of other methods) are designed to not modify the contents. This is guaranteed if they take a value (but this will be slow for large types) or a const reference.
Note that you defined the comparison method to compare the size of the vectors, not their contents. All your vectors are of equal length. So they are treated to be equal by std::sort. So std::sort wouldn't change v4... If you intend to compare the contents in a way similar to string comparison (the first entry counts first, if equal then take the next and so on...), use this:
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const
{
for(int i = 0; i < size && i < source.size; ++i) {
if(*this[i] < source[i])
return true;
else if(source[i] < *this[i])
return false;
}
// You have to decide what to do if the length isn't equal.
// But if the vectors are really equal than return false:
if(size == source.size)
return false;
}
Your forgot a const!
template <class T>
bool Vector<T>::operator<(const Vector<T> & source) const // <- here
{
return (vector_size < source.vector_size);
}
One thing you'd need is to use const in the parameter to your operator, otherwise it can't match anything that is read-only (which would be the common case).
Keep in mind though that sorting vectors-of-vectors would copy entire vectors every time swaps occur. This will not be particularly efficient. If the vectors were stored separately and you had something like vector-of-pointer-to-vector, at least the sorting would be faster.
Be sure to read the definition of "strict weak ordering", too. It is very important for the ordering to be consistent with itself, or standard algorithms like std::sort() can badly misbehave (to the point of corrupting memory in some implementations).