Sleek way to use template function as function argument? - c++

What I really want to do is to compare the performance of different algorithms which solve the same task in different ways. Such algorithms, in my example called apply_10_times have sub algorithms, which shall be switchable, and also receive template arguments. They are called apply_x and apply_y in my example and get int SOMETHING as template argument.
I think the solution would be to specify a template function as template parameter to another template function. Something like this, where template_function is of course pseudo-code:
template<int SOMETHING>
inline void apply_x(int &a, int &b) {
// ...
}
template<int SOMETHING>
inline void apply_y(int &a, int &b) {
// ...
}
template<template_function APPLY_FUNCTION, int SOMETHING>
void apply_10_times(int &a, int &b) {
for (int i = 0; i < 10; i++) {
cout << SOMETHING; // SOMETHING gets used here directly as well
APPLY_FUNCTION<SOMETHING>(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times<apply_x, 17>(a, b);
apply_10_times<apply_y, 19>(a, b);
apply_10_times<apply_x, 3>(a, b);
apply_10_times<apply_y, 2>(a, b);
return 0;
}
I've read that it's not possible to pass a template function as a template parameter, so I can't pass APPLY_FUNCTION this way. The solution, afaik, is to use a wrapping struct, which is then called a functor, and pass the functor as a template argument. Here is what I got with this approach:
template<int SOMETHING>
struct apply_x_functor {
static inline void apply(int &a, int &b) {
// ...
}
};
template<int SOMETHING>
struct apply_y_functor {
static inline void apply(int &a, int &b) {
// ...
}
};
template<typename APPLY_FUNCTOR, int SOMETHING>
void apply_10_times(int &a, int &b) {
for (int i = 0; i < 10; i++) {
cout << SOMETHING; // SOMETHING gets used here directly as well
APPLY_FUNCTOR:: template apply<SOMETHING>(a, b);
}
}
This approach apparently works. However, the line APPLY_FUNCTOR:: template apply<SOMETHING>(a, b); looks rather ugly to me. I'd prefer to use something like APPLY_FUNCTOR<SOMETHING>(a, b); and in fact this seems possible by overloading the operator(), but I couldn't get this to work. Is it possible and if so, how?

As it is not clear why you need APPLY_FUNCTION and SOMETHING as separate template arguments, or why you need them as template arguments at all, I'll state the obvious solution, which maybe isn't applicable to your real case, but to the code in the question it is.
#include <iostream>
template<int SOMETHING>
inline void apply_x(int a, int b) {
std::cout << a << " " << b;
}
template<int SOMETHING>
inline void apply_y(int a, int b) {
std::cout << a << " " << b;
}
template<typename F>
void apply_10_times(int a, int b,F f) {
for (int i = 0; i < 10; i++) {
f(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times(a, b,apply_x<17>);
apply_10_times(a, b,apply_y<24>);
}
If you want to keep the function to be called as template argument you can use a function pointer as non-type template argument:
template<void(*F)(int,int)>
void apply_10_times(int a, int b) {
for (int i = 0; i < 10; i++) {
F(a, b);
}
}
int main() {
int a = 4;
int b = 7;
apply_10_times<apply_x<17>>(a, b);
apply_10_times<apply_y<24>>(a, b);
}
In any case I see no reason to have APPLY_FUNCTION and SOMETHING as separate template arguments. The only gain is more complex syntax which is exactly what you want to avoid. If you do need to infer SOMETHING from an instantiation of either apply_x or apply_y, this is also doable without passing the template and its argument separately, though again you'd need to use class templates rather than function templates.
PS:
Ah, now I understand what you mean. Yes, apply_10_times() also uses SOMETHING directly. Sorry, I simplified the code in the question too much.
As mentioned above. This does still not imply that you need to pass them separately. You can deduce SOMETHING from a apply_x<SOMETHING> via partial template specialization. This however requires to use class templates not function templates:
#include <iostream>
template <int SOMETHING>
struct foo {};
template <int X>
struct bar {};
template <typename T>
struct SOMETHING;
template <template <int> class T,int V>
struct SOMETHING<T<V>> { static constexpr int value = V; };
int main() {
std::cout << SOMETHING< foo<42>>::value;
std::cout << SOMETHING< bar<42>>::value;
}

What I really want to do is to compare the performance of different
algorithms which solve the same task in different ways.
You should provide more details about that.
Your first step should be get familiar with Google Benchmark. There is as site which provides it online. This tool give proper patterns for your scenario.
In next step you must be aware that in C and C++ there is "as if rule" which allows optimizer do do wonderful things, but makes creation of good performance test extremely difficult. It is easy write test which doesn't measure actual production code.
Here is cppcon talk showing how many traps are hidden when doing a good performance test fro C++ code. So be very very careful.

Related

Template (de)activated member variables

I am looking for a convenient to create a C++ class where some member variables are only present if a template flag is set. As a simple example, let's assume I want to toggle an averageSum in an performance sensitive calculation, i.e.
struct Foo {
// Some data and functions..
void operator+=(const Foo& _other) {}
};
template<bool sumAverages>
class Calculator {
public:
// Some member variables...
// Those should only be present if sumAverages is true
int count = 0;
Foo resultSum;
void calculate(/* some arguments */) {
// Calculation of result...
Foo result;
// This should only be calculated if sumAverages is true
++count;
resultSum += result;
// Possibly some post processing...
}
};
One way would be using preprocessor defines, but those are rather inconvenient especially if I need both versions in the same binary. So I am looking for an alternative using templates and if constexpr and something like the following Conditional class:
template<bool active, class T>
struct Conditional;
template<class T>
struct Conditional<true, T> : public T {};
template<class T>
struct Conditional<false, T> {};
My first shot was this:
template<bool sumAverages>
class Calculator {
public:
int count = 0;
Conditional<sumAverages, Foo> resultSum;
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++count;
resultSum += result;
}
}
};
The if constexpr should incur no run time cost and as it is dependent on a template variable should allow non-compiling code in the false case (e.g. in this example Conditional<false, Foo> does not define a += operator, still it compiles). So this part is more or less perfect. However the variables count and resultSum are still somewhat present. In particular, as one can not derive from a fundamental type, the Conditional class does not allow to toggle the int dependent on the template. Furthermore every Conditional<false, T> variable still occupies one byte possibly bloating small classes. This could be solvable by the new [[no_unique_address]] attribute, however my current compiler chooses to ignore it in all my tests, still using at leas one byte per variable.
To improve things I tried inheriting the variables like this
struct OptionalMembers {
int count;
Foo resultSum;
};
template<bool sumAverages>
class Calculator : public Conditional<sumAverages, OptionalMembers> {
public:
void calculate(/* some arguments */) {
Foo result;
if constexpr(sumAverages) {
++OptionalMembers::count;
OptionalMembers::resultSum += result;
}
}
};
This should come at no space cost as inheriting from am empty class should do literally nothing, right? A possible disadvantage is that one cannot freely set the order of the variables (the inherited variables always come first).
My questions are:
Do you see any problems using the approaches described above?
Are there better options to de(activate) variables like this?
There are a different ways to solve this, one straightforward one would be using template specialization:
#include <iostream>
template <bool b> struct Calculator {
int calculate(int i, int j) { return i + j; }
};
template <> struct Calculator<true> {
int sum;
int calculate(int i, int j) { return sum = i + j; }
};
int main(int argc, char **argv) {
Calculator<false> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<true> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}
Another solution would be to use mixin-like types to add features to your calculator type:
#include <iostream>
#include <type_traits>
struct SumMixin {
int sum;
};
template <typename... Mixins> struct Calculator : public Mixins... {
int calculate(int i, int j) {
if constexpr (is_deriving_from<SumMixin>()) {
return SumMixin::sum = i + j;
} else {
return i + j;
}
}
private:
template <typename Mixin> static constexpr bool is_deriving_from() {
return std::disjunction_v<std::is_same<Mixin, Mixins>...>;
}
};
int main(int argc, char **argv) {
Calculator<> cx;
cx.calculate(3, 4);
/* std::cout << cx.sum << '\n'; <- will not compile */
Calculator<SumMixin> cy;
cy.calculate(3, 4);
std::cout << cy.sum << '\n';
return 0;
}

How do I call template array operator overloading function?

I need to create an adapter C++ class, which accepts an integer index, and retrieves some types of data from a C module by the index, and then returns it to the C++ module.
The data retrieving functions in the C module are like:
int getInt(int index);
double getDouble(int index);
const char* getString(int index);
// ...and etc.
I want to implement an array-like interface for the C++ module, so I created the following class:
class Arguments {
public:
template<typename T> T operator[] (int index);
};
template<> int Arguments::operator[] (int index) { return getInt(index); }
template<> double Arguments::operator[] (int index) { return getdouble(index); }
template<> std::string Arguments::operator[] (int index) { return getString(index); }
(Template class doesn't help in this case, but only template member functions)
The adapter class is no biggie, but calling the Arguments::operator[] is a problem!
I found out that I can only call it in this way:
Arguments a;
int i = a.operator[]<int>(0); // OK
double d = a.operator[]<double>(1); // OK
int x = a[0]; // doesn't compile! it doesn't deduce.
But it looks like a joke, doesn't it?
If this is the case, I would rather create normal member functions, like template<T> T get(int index).
So here comes the question: if I create array-operator-overloading function T operator[]() and its specializations, is it possible to call it like accessing an array?
Thank you!
The simple answer is: No, not possible. You cannot overload a function based on its return type. See here for a similar quesiton: overload operator[] on return type
However, there is a trick that lets you deduce a type from the lhs of an assignment:
#include <iostream>
#include <type_traits>
struct container;
struct helper {
container& c;
size_t index;
template <typename T> operator T();
};
struct container {
helper operator[](size_t i){
return {*this,i};
}
template <typename T>
T get_value(size_t i){
if constexpr (std::is_same_v<T,int>) {
return 42;
} else {
return 0.42;
}
}
};
template <typename T>
helper::operator T(){
return c.get_value<T>(index);
}
int main() {
container c;
int x = c[0];
std::cout << x << "\n";
double y = c[1];
std::cout << y ;
}
Output is:
42
0.42
The line int x = c[0]; goes via container::get_value<int> where the int is deduced from the type of x. Similarly double y = c[1]; uses container::get_value<double> because y is double.
The price you pay is lots of boilerplate and using auto like this
auto x = c[1];
will get you a helper, not the desired value which might be a bit unexpected.

How to use declare a function template pointer typedef without specifying template?

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
enum Op{ADD, SUB, MUL, DIV, MATMUL};
template <typename dtype>
using AlgoFunction = double(*)(const vector<dtype> &, Op);
// for example, the sum function doesn't require template.
// just write sum(a), not sum<float>(a)
template <typename dtype>
double sum(vector<dtype> inputs) {
dtype summer = inputs[0];
for (int i=1; i<inputs.size(); i++) summer = summer + inputs[i];
return double(summer);
}
// i need to do ask this question because I perform the same
// algorithm (linearAlgo, ...) on different types of data
// (dtype = float, double, matrix<float>, matrix<double>, ...
template <typename dtype>
inline dtype numOperate(const dtype &a, const dtype &b, Op op) {
if (op==ADD) return a + b;
if (op==SUB) return a - b;
if (op==MUL) return a * b;
if (op==DIV) return a / b;
}
template <typename dtype>
double linearAlgo(const vector<dtype> &inputs, Op op) {
dtype summer = inputs[0];
for (int i=1; i<inputs.size(); i++) summer = numOperate(summer, inputs[i], op);
return double(summer);
}
template <typename dtype>
double reverseLinearAlgo(const vector<dtype> &inputs, Op op) {
int n = inputs.size();
dtype summer = inputs[n-1];
for (int i=n-2; i>=0; i--) summer = numOperate(summer, inputs[i], op);
return double(summer);
}
template<typename dtype>
vector<double> run(vector<dtype> inputs, Op op, double (*func)(const vector<dtype>&, Op)) {
vector<double> res;
res.push_back(func(inputs, op));
return res;
}
int main()
{
vector<float> a;
vector<double> b;
a.push_back(1); a.push_back(2); a.push_back(3);
b.push_back(1); b.push_back(2); b.push_back(3);
vector<double> res = run(a, ADD, linearAlgo); // allowed without specifying template
vector<double> resf = run(b, ADD, linearAlgo); // still work with multiple data type
// I want to do this assignment without specifying the template.
// in the above linear, linearAlgo (no specifying template) is possible, why not here ?
AlgoFunction<float> functor = reverseLinearAlgo; // works, but I don't want it
//AlgoFunction functor = reverseLinearAlgo; // I want to do this. compile error
vector<double> res2 = run(a, ADD, functor);
cout << res[0] << "\n";
cout << res2[0];
return 0;
}
So I have a function template pointer
template <typename dtype>
using AlgoFunction = double(*)(const vector<dtype> &, Op);
that points to functions like this
template <typename dtype>
double linearAlgo(const vector<dtype> &inputs, Op op) {
dtype summer = inputs[0];
for (int i=1; i<inputs.size(); i++) summer = numOperate(summer, inputs[i], op);
return double(summer);
}
I know that using a template function pointer without specifying template is possible. For example:
vector<float> a;
a.push_back(1); a.push_back(2); a.push_back(3);
vector<double> res = run(a, ADD, linearAlgo); // allowed without specifying template
But then if I declare a variable of type AlgoFunction, the compiler force me to specify the template.
//AlgoFunction<float> functor = reverseLinearAlgo; // works, but I don't want it
AlgoFunction functor = reverseLinearAlgo; // I want to do this. compile error
This is not good because I have many types of data dtype, and I don't want to specify the template again for each one.
So how can I declare AlgoFunction functor; instead of AlgoFunction<some_datatype_name> functor; ?
Thank you.
Edit: the goal is to have a vector<AlgoFunction> functors instead of vector<AlgoFunction<data_type> >. Since in the example, res, and resf both can be calculated without specifying the template for the 3rd parameter, I want to know if vector<AlgoFunction> is possible or not.
You cannot. I suspect the confusion stems from missing the difference between a "function" and a "function template".
To explain why your first example worked, first let's examine what is actually happening when you do run(a, ADD, linearAlgo);. As a reminder, we have:
template <typename dtype>
using AlgoFunction = double(*)(const std::vector<dtype>&, Op);
template <typename dtype>
std::vector<double> run(const std::vector<dtype>&, Op,
double(*)(const std::vector<dtype>&, Op));
Equivalently, we could have had the following:
std::vector<double> run(const std::vector<dtype>&, Op, AlgoFunction<dtype>);
since AlgoFunction is just an alias.
Now, when we do this:
std::vector<double> a;
run(a, ADD, linearAlgo);
we know that the first argument to run, std::vector<dtype>, is std::vector<double>, and hence dtype is double. We can't determine anything about dtype from the third argument since linearAlgo is just a template, a "pattern".
Since we know that dtype must be double, we can choose and instantiate linearAlgo<dtype> – that is, linearAlgo<double> – as our function since that fits our signature, and everything is OK.
Now, what does that have to do with this?
AlgoFunction functor = reverseLinearAlgo;
In this case, we're trying to create a variable. reverseLinearAlgo is just a function template, not an actual function, and we don't have any other context to determine what type functor actually is. Hence the compiler error.
Moreover, what would this actually mean? Would functor have a different type depending on where you used it? If I did auto x = functor;, what type would x have? If I did something like
AlgoFunction functor = reverseLinearAlgo;
if (test) {
std::vector<float> x;
functor(x, ADD);
} else {
std::vector<double> x;
functor(x, ADD);
}
would that mean that functor has dynamic type? This isn't something that works with C++'s (static) type system, and it can quickly get out of hand if this was made legal. This is the case with your wish for std::vector<AlgoFunction>: you have to store a concrete type. Otherwise the program will need to dynamically instantiate a function based on runtime information: template parameters must be known at compile time.
One possible alternative, if you know the types ahead of time, is to use a std::variant of the possible types you might instantiate with. That is, something like
std::vector<std::variant<AlgoFunction<float>, AlgoFunction<double>>>;
if each element of the vector should provide one or the other, or else use
std::vector<std::tuple<AlgoFunction<float>, AlgoFunction<double>>>;
if each element of the vector should be usable with either type.
Whether this is useful, and worth the added complexity, is up to you.
It's possible to do what you want, but it is messy to implement in C++ because you have to do manual type checking if you want to seriously implement something like this.
Here is a quick method to do what you want, but beware that you need more than this to make something useful for serious work, and it's extremely easy to shoot yourself in the foot with this kind of code:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct AlgoFunction {
virtual double operator()(void *) = 0;
};
template <class T>
struct AF_Sum : public AlgoFunction {
virtual double operator()(void * inputVec) {
T res = T();
vector<T>* pInput = (vector<T>*)inputVec;
for (int i = 0; i < pInput->size(); ++i) {
res += (*pInput)[i];
}
return (double) res;
}
};
template <class T>
struct AF_Mean : public AlgoFunction {
virtual double operator()(void * inputVec) {
T res = T();
vector<T>* pInput = (vector<T>*)inputVec;
for (int i = 0; i < pInput->size(); ++i) {
res += (*pInput)[i];
}
return (double) res / (double)pInput->size();
}
};
int main()
{
std::vector<float> vF{0.2, 0.3, 0.8};
std::vector<int> vI{2, 5, 7};
std::vector<AlgoFunction*> algoFunctions;
algoFunctions.push_back(new AF_Sum<float>);
algoFunctions.push_back(new AF_Mean<int>);
cout << (*algoFunctions[0])(&vF) << endl;
cout << (*algoFunctions[1])(&vI) << endl;
return 0;
}
Notice that I didn't bother cleaning the heap-allocated memory (via new) and I didn't implement all of your functions; just a quick and dirty example of a potential solution.

Passing function to template object when initializing template in C++

I'm trying to write an implementation for hash map, I'm not allowed to use anything from stdlib except for iostream, string and cassert.
It needs to be generic, so the values that populate the buckets can be of any type. I need templates for this, but can't manage to pass the hash function in any way. This would be the header file:
template<typename Value, typename hashFunction>
class hashTable{
public:
hashTable(int size){
//Creates an empty vector of size on the table
}
define(Value v){
loads value in Vector[hashFunction(v)];
}
...
private:
Vector with all the elements
}
Note: I guess I don't need templates for the keys, do I?
I can't define the hash function inside my class because I'd have to make one that works with all types (string to int, int to int, double to int, etc). So I guess the only solution is to pass the function as argument in my main. This would be the main.
int hashF(int v){return v}
int main(){
hashTable<int,int,hashF> table(5);
}
But this doesn't work, g++ tells me "expected type but got hashF". I guess I could pass a pointer to a function, but that seems like a hack rather than a real solution. Is there a better way?
template<typename Value, int(*fun)(Value)>
class hashTable {
std::vector<Value> v;
public:
hashTable(std::size_t size) : v(size) { }
void define(Value &&val) { v[fun(val)] = val; }
};
Live Demo
Non function pointer way:
template<typename Value, typename F>
class hashTable {
std::vector<Value> v;
F fun;
public:
hashTable(std::size_t size, F fun_) : v(size), fun(fun_) { }
void define(Value &&val) { v[fun(val)] = val; }
};
Live Demo
Managed to get it working with Neil's advice. My hash.h:
template<typename C, typename D, typename H>
class Tabla {
public:
Tabla(int s){
cout << hashF(3) << endl;
size=s;
}
private:
H hashF;
int size;
};
My hash.cpp
struct KeyHash {
unsigned long operator()(const int& k) const
{
return k % 10;
}
};
int main(){
Tabla<int,int,KeyHash> tab(3);
return 0;
}
This example is just to show I'm able to use the function inside the template, then I'd have to code the define and delete functions that use that KeyHash.
Dunno why I have to wrap it like this, but it works. Found the specifics of it here

Template filled by an operator

Can you use templates (or the like) in C++ to specify which operation is done in a function?
I don't know how to explain it more clearly, so I'll show you how it could be (but isn't) done in code:
template <operator OPERATION> int getMaxOrMin(int a, int b) {
return a OPERATION b ? a : b;
}
where finding the maximum or the minimum of a or b would be (this is where my pseudo-syntax gets a little confusing, bear with me):
int max = getMaxOrMin< > > (a, b);
int min = getMaxOrMin< < > (a, b);
I know that's not how to do it at all (because it doesn't even syntactically make sense), but I hope that clarifies the type of thing I want to do.
The reason behind me wondering this is I'm making a PriorityQueue implementation, and it would be nice to easily switch between the backing being a max-heap or a min-heap on the fly without copying and pasting code to make two different classes.
I know I could do it with a macro, but the only way I'd know how to do that would give me either a max-heap or a min-heap, but not both in the same compilation. I'm probably overlooking a way, though.
Do what std::map and friends do: Take a comparison function/functor as your template parameter. See std::less and std::greater.
Do remember that the standard library already has a well developed and debugged priority queue that you can use with an arbitrary comparison function.
Yes but you need to define it like a functor:
template <typename OPERATION>
int getMaxOrMin(int a, int b)
{
OPERATION operation;
return operation(a, b) ? a : b;
}
Now you can use it like this:
struct myLess
{
bool operator()(int a,int b) const { return a < b; }
}
struct myGreat
{
bool operator()(int a,int b) const { return a > b; }
}
void code()
{
int x = getMaxOrMin<myLess>(5,6);
int y = getMaxOrMin<myGreat>(5,6);
}
That seems like a lot of work. But there are a lot of predefined functors in the standard. On this page scroll down to "6: Function Objects".
For your situation there is:
std::less
std::greater
So the code becomes:
template <typename OPERATION>
int getMaxOrMin(int a, int b)
{
OPERATION operation;
return operation(a, b) ? a : b;
}
void codeTry2()
{
int x = getMaxOrMin<std::less<int> >(5,6);
int y = getMaxOrMin<std::greater<int> >(5,6);
}