Using array to convert MapResult to an array - templates

I'm having a bit of trouble using array from std.array to convert a MapResult to a specific array type. My problem is as follows:
I have an array a of objects, each of which has a publically-accessible field val. I would like to use map from std.algorithm to go over a and return an array of all the values of the val members. My code looks something like this:
import std.algorithm:map;
import std.array:array;
//import for my object type, which I call Box here
ulong[] fun (Box[] a) {
return array!(ulong[])(map!(function ulong(Box x) {return x.val;})(a);
}
However, when I try to do this, the compiler gives me an error saying that array cannot deduce the function from the argument types !(ulong[])(MapResult!(_funcliteral3,Box[])). Does that mean that MapResults aren't ranges, and is there a way to get what I want?

actually it means that the compiler believed that (ulong[])(MapResult!(_funcliteral3,Box[])) was the template parameter instead of ulong[]
nest your parenthesis properly and it should be fixed
return array!(ulong[])(map!(function ulong(Box x) {return x.val;})(a));

Related

Paramter pack unfolding correctly to initialize a std::array of std::strings

currently i am playing around with parameter packs in c++. I have wrote this little snippet:
template<typename ...Targs>
auto toString(Targs... args) -> std::array<std::string,sizeof...(Targs)>
{
return {
{
(std::forward<std::string>(std::to_string(args)),...)
}
};
}
It has no real purpose but the exercise was/is to create an array of strings from the given parameter which can vary in count and type.
What I hoped to achieve was to do the following:
std::array<std::string,3> SomeName = { {std::to_string(1),std::to_string(2),std::to_string(3)} };
but more generic. That was the idea for the toString function. Unfortunately the result I get is not what I expected. The returned std::array will only contain the last parameter given to toString with the rest of the strings being empty.
But what I actually expected was that each argument given to toString gets converted into an string and put into the element of the array.
What did I miss about parameter pack unfolding? Or do I have just annoyingly stupid mistake?
You have an extra comma:
(std::forward<std::string>(std::to_string(args)),...)
// ^
This now becomes a fold expression over a comma, which is a single expression that gives you one string, where you want N strings. Also, the term isn't unfolding, the term is parameter pack expansion.
Removing the comma gives you what you want:
return {{std::to_string(args)...}};
Note that the std::forward<> is unnecessary - so I removed that too.

Using a function pointer from one class in a function of another class

I have looked at the following threads, but they do not seem to help resolve the issue:
Function pointer to member function - this thread does not help because the access is made within main and not another class
one class should invoke method of another class using a function pointer - I could not follow the accepted answer as it is not clear to me how to use <functional> header.
I have a Useful Function class, UF, in which I declare and define all common utility functions for my program. One of these functions is
int UF::compar_dbl_asc(const void *a, const void *b)//comparator for sorting
{ //array of double in ascending order
int aa = *((int *)a), bb = *((int *)b);
if (base_arr_dbl[aa] < base_arr_dbl[bb])
return -1;
if (base_arr_dbl[aa] == base_arr_dbl[bb])
return 0;
if (base_arr_dbl[aa] > base_arr_dbl[bb])
return 1;
}
This is a comparator function that I intend to use within qsort() for sorting doubles in ascending order.
Within UF class definition, I also have double* base_arr_dbl; as a declaration. This is the array of values (doubles) that qsort will use.
Now, in a different class of mine named SEP, I have a function, fn1 wherein I would like to have base_arr_dbl point to a local (to fn1) double array and I would like to invoke qsort using the comparator function in UF. To be very specific although this is possibly not needed, I do not sort the actual values' array, but will sort an array of indices sortedindices[], such that sortedindices[0] will hold the index of the smallest entry in base_arr_dbl[] array. That is, the sorted order is base_arr_dbl[sortedindices[0]], base_arr_dbl[sortedindices[1]], etc.
So, I do this:
void SEP::fn1(UF *uf) {
double ratio[100];
//populate ratio's entries
//Now, sort ratio's entries.
uf->set_base_arr_dbl(ratio); //This function is defined as
//void UF::set_base_arr_dbl(double *ptr) { base_arr_dbl = ptr; }
qsort(sortedindices, 100, sizeof(double), uf->compar_dbl_asc);
}
However, the line qsort(sortedindices, 100, sizeof(double), uf->compar_dbl_asc); throws the following compile time error:
error C3867: 'USEFUL_FUNCTIONS::compar_dbl_asc': non-standard syntax; use '&' to create a pointer to member
I tried having &uf->compar_dbl_asc but that gives the error:
error C2276: '&': illegal operation on bound member function expression
Any way to help resolve this is appreciated.
As the compiler clearly tells in the error messages, neither uf->compar_dbl_asc nor &(uf->compar_dbl_asc) is appropriate for use as an argument to qsort.
You can use compar_dbl_asc as an argument to qsort using one of the following approaches.
Make compar_dbl_asc a static member function of the class.
Better yet, create a namespace for your app and define compar_dbl_asc in the namespace. UF could be that namespace unless it must be a class for some other reasons.
Another choice would be forego use of qsort in favor of std::sort. The latter gives you more options. You can use a functor or a lambda function when you use std::sort, which will allow you to use UF::compar_dbl_asc.
std::sort(sortedindices, sortedindices+100,
[=uf](int a, int b) { return uf->compar_dbl_asc(a, b); });
One thing to note is that if you choose the last approach, the signature of UF::compar_dbl_asc can be changed to a more user friendly variation.
bool UF::compar_dbl_asc(int a, int b)
return (base_arr_dbl[a] < base_arr_dbl[b]);
}

Can't extend generic struct for specific type

Wanted to toy with adding some sugar in Swift3. Basically, I wanted to be able to do something like:
let randomAdjust = (-10...10).random
To do that, I decided I would need to extend ClosedRange. But then found it would probably be even better for my case, I really just plan on doing Int's for now, to use CountableClosedRange. My latest of multiple attempts looked like:
extension CountableClosedRange where Bound == Int {
var random:Int {
return Int(arc4random_uniform(UInt32(self.count) + 1)) + self.lowerBound
}
}
But the playground complains:
error: same-type requirement makes generic parameter 'Bound' non-generic
extension CountableClosedRange where Bound == Int {
I don't even know what it's telling me there.
The way this roadblock is commonly encountered is when attempting to extend Array. This is legal:
extension Array where Element : Comparable {
}
But this is illegal:
extension Array where Element == Int {
}
The compiler complains:
Same-type requirement makes generic parameter 'Element' non-generic
The problem is the use of == here in combination with Array's parameterized type Element, because Array is a generic struct.
One workaround with Array is to rise up the hierarchy of Array's inheritance to reach something that is not a generic struct:
extension Sequence where Iterator.Element == Int {
}
That's legal because Sequence and Iterator are generic protocols.
Another solution, though, is to rise up the hierarchy from the target type, namely Int. If we can find a protocol to which Int conforms, then we can use the : operator instead of ==. Well, there is one:
extension CountableClosedRange where Bound : Integer {
}
That's the real difference between our two attempts to implement random on a range. The reason your attempt hits a roadblock and mine doesn't is that you are using == whereas I am using :. I can do that because there's a protocol (FloatingPoint) to which Double conforms.
But, as you've been told, with luck all this trickery will soon be a thing of the past.
In Swift 4, what you are attempting is now completely supported. Hooray!
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
Example from Swift docs: https://docs.swift.org/swift-book/LanguageGuide/Generics.html#ID553

How do you create an array of member function pointers with arguments?

I am trying to create a jump table for a fuzzy controller. Basically, I have a lot of functions that take in a string and return a float, and I want to be able to do something along the lines:
float Defuzzify(std::string varName, DefuzzificationMethod defuzz)
{
return functions[defuzz](varName);
}
where DefuzzificationMethod is an enum. The objective is to avoid a switch statement and have a O(1) operation.
What I have right now is:
float CenterOfGravity(std::string varName);
std::vector<std::function<float (std::string)>> defuzzifiers;
Then I try to initialize it in the constructor with:
defuzzifiers.reserve(NUMBER_OF_DEFUZZIFICATION_METHODS);
defuzzifiers[DEFUZZ_COG] = std::bind(&CenterOfGravity, std::placeholders::_1);
This is making the compiler throw about 100 errors about enable_if (which I don't use anywhere, so I assume std does). Is there a way to make this compile ? Moreover, is there a way to make this a static vector, since every fuzzy controller will essentially have the same vector ?
Thanks in advance
Reserve just makes sure there's enough capacity, it doesn't actually mak the vector's size big enough. What you want to do is:
// construct a vector of the correct size
std::vector<std::function<float (std::string)>> defuzzifiers(NUMBER_OF_DEFUZZIFICATION_METHODS);
// now assign into it...
// if CentorOfGravity is a free function, just simple = works
defuzzifiers[DEFUZZ_COG] = CenterOfGravity;
// if it's a method
defuzzifiers[DEFUZZ_COG] = std::bind(&ThisType::CenterOfGravity, this, std::placeholders::_1);
Now this might leave you some holes which don't actually have a function defined, so maybe you want to provide a default function of sorts, which the vector constructor allows too
std::vector<std::function<float (std::string)>> defuzzifiers(
NUMBER_OF_DEFUZZIFICATION_METHODS,
[](std::string x) { return 0f; }
);
An unrelated note, you probably want your functions to take strings by const-ref and not by value, as copying strings is expensive.

C++ using std::accumulate to generate a map<int,int>

I have a problem creating a std::map<int, int> from a vector of pointers, called files. Each pointer points to an object with three member variables, one of which is size of type int. The key of the map would be the size and the value would be the number of objects which have the same size.
Do NOT waste your time on the second one! It is the next step in my program and I have figured it out already, I think. For initialization of the map I am using std::accumulate, because it returns a value. I am using std::tr1::shared_ptr for the pointers and a lambda expression for the predicate function. I am having problems with compilation.
Here's the code snippet:
map<int,int>* sizes = new map<int,int>();
sizes = accumulate(files.begin(), files.end(),sizes,
[&sizes](map<int,int> acc, shared_ptr<CFileType>& obj)
{
return sizes->insert(pair<int,int>(obj->getSize(),0));
});
Here's the error:
error C2664: 'std::pair<_Ty1,_Ty2> `anonymous-namespace'::::operator ()(std::map<_Kty,_Ty>,std::tr1::shared_ptr &) const' : cannot convert parameter 1 from 'std::map<_Kty,_Ty> ' to 'std::map<_Kty,_Ty>'
I am not very sure what to pass to the lambda function. I have tried with pair<int, int>, but it didn't work. Also, I must mention that this map is returned to another function, so it has to be a pointer.
Any help from you would be appreciated. Thanks!
UPDATE:
Problem solved, here is the solution:
map<int,int>* sizes = accumulate(files.begin(), files.end(), new map<int,int>(),
[](map<int,int>* acc, shared_ptr<CFileType>& obj)->map<int,int>*
{
acc->insert(pair<int,int>(obj->getSize(),0));
return acc;
});
The error message is that you have a type mismatch between the two kinds of std::maps. It looks like the error is in the code that calls the lambda, which apparently passes the wrong thing for the acc parameter. The good news is that the lambda, as posted, never actually uses the acc parameter.