Obtaining an operator from compile-time constant?

I want to generalize my productFunction below to a template family of functions where the template merely changes the * to + or whatever else operator I wish to use.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <functional>

#define show(variable) std::cout << #variable << " = " << variable << std::endl;

template <typename, typename...> struct ProductFunction;

template <typename RETURN_TYPE, typename FIRST, typename... REST>
struct ProductFunction<RETURN_TYPE, FIRST, REST...> : ProductFunction<RETURN_TYPE, REST...> {
	const FIRST function;
	using Base = ProductFunction<RETURN_TYPE, REST...>;
	ProductFunction (FIRST first, REST... rest) : Base(rest...), function(first) {}
	template <typename... ARGS>
	RETURN_TYPE operator() (ARGS&&... args) const {
		return function(std::forward<ARGS>(args)...) * Base::operator()(std::forward<ARGS>(args)...); 
	}  // Changing * to + will similarly yield a sumFunction.
};

template <typename RETURN_TYPE, typename LAST>
struct ProductFunction<RETURN_TYPE, LAST> {
	const LAST function;
	ProductFunction (LAST f) : function(f) {}
	template <typename... ARGS>
	RETURN_TYPE operator() (ARGS&&... args) const {
		return function(std::forward<ARGS>(args)...);
	}
};

template <typename RETURN_TYPE, typename... ARGS, typename... FUNCTIONS>
std::function<RETURN_TYPE(ARGS...)> productFunction (FUNCTIONS&&... f) {
	return ProductFunction<RETURN_TYPE, FUNCTIONS...> (std::forward<FUNCTIONS>(f)...);
}

int main() {
	std::function<bool(int, double)> f = [](int n, double d) {return n + d < 10;};
	std::function<bool(int, double)> g = [](int n, double d) {return n - d > 0;};
	std::function<bool(int, double)> h = [](int n, double d) {return n * d > 15;};
	
	std::function<bool(int, double)> F = productFunction<bool, int, double>(f, g, h);
	std::cout << std::boolalpha;
	show (F(6, 3.5))  // true
	show (F(6, 1.5))  // false
	show (F(3, 6.5))  // false
}

How can I turn a template parameter into various operators? (apart from using switch statements that will reduce the performance and make the code really ugly) What kind of metatemplating method converts a compile-time constant to an operator?
Last edited on
make the code really ugly

I think what you have now looks really ugly, especially with that horrid coding style.
I solved my own problem, but I can't seem to delete this thread, so I posted my solution below anyway.

@exchgg. Please tell me what is wrong with my coding style. I'm honestly open to suggestions because I'm still learning. The super-indentations are not by me, but the copy and paste effect from my editor onto here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <functional>

#define show(variable) std::cout << #variable << " = " << variable << std::endl;

enum OperatorType {ProductOperator, SumOperator, AndOperator, OrOperator};

template <int, typename> struct ComposeOperator;

template <typename T>
struct ComposeOperator<ProductOperator, T> {
	bool operator() (const T& x, const T& y) {return x * y;}
};

template <typename T>
struct ComposeOperator<SumOperator, T> {
	bool operator() (const T& x, const T& y) {return x + y;}
};

template <>
struct ComposeOperator<AndOperator, bool> {
	bool operator() (bool x, bool y) {return x && y;}
};

template <>
struct ComposeOperator<OrOperator, bool> {
	bool operator() (bool x, bool y) {return x || y;}
};

template <int, typename, typename...> struct ComposedFunction;

template <int N, typename RETURN_TYPE, typename FIRST, typename... REST>
struct ComposedFunction<N, RETURN_TYPE, FIRST, REST...> : ComposedFunction<N, RETURN_TYPE, REST...> {
	const FIRST function;
	using Base = ComposedFunction<N, RETURN_TYPE, REST...>;
	ComposedFunction (FIRST first, REST... rest) : Base(rest...), function(first) {}
	template <typename... ARGS>
	RETURN_TYPE operator() (ARGS&&... args) const {
		return ComposeOperator<N, RETURN_TYPE>()(function(std::forward<ARGS>(args)...), Base::operator()(std::forward<ARGS>(args)...)); 
	} 
};

template <int N, typename RETURN_TYPE, typename LAST>
struct ComposedFunction<N, RETURN_TYPE, LAST> {
	const LAST function;
	ComposedFunction (LAST f) : function(f) {}
	template <typename... ARGS>
	RETURN_TYPE operator() (ARGS&&... args) const {
		return function(std::forward<ARGS>(args)...);
	}
};

template <int N, typename RETURN_TYPE, typename... ARGS, typename... FUNCTIONS>
std::function<RETURN_TYPE(ARGS...)> composedFunction (FUNCTIONS&&... f) {
	return ComposedFunction<N, RETURN_TYPE, FUNCTIONS...> (std::forward<FUNCTIONS>(f)...);
}

int main() {
	std::function<bool(int, double)> f = [](int n, double d) {return n + d < 10;};
	std::function<bool(int, double)> g = [](int n, double d) {return n - d > 0;};
	std::function<bool(int, double)> h = [](int n, double d) {return n * d > 15;};
	
	std::function<bool(int, double)> F = composedFunction<AndOperator, bool, int, double>(f, g, h);
	std::function<bool(int, double)> G = composedFunction<OrOperator, bool, int, double>(f, g, h);
	std::cout << std::boolalpha;
	show (F(6, 3.5))  // true
	show (F(6, 1.5))  // false
	show (F(3, 6.5))  // false
	show (G(6, 1.5))  // true
	show (G(3, 6.5))  // true
}
Last edited on
@exchgg. Please respond, since you don't accept private messages. I would like to hear more from you.

Or perhaps someone else could tell me what's wrong with my coding style? Is it the use of capital letters? They should not be used for template parameters, only for constants and macros?
Last edited on
Topic archived. No new replies allowed.