Comparing 2 values using template metaprogramming C++ - c++

I want to have a default function as a "Predicate" template in case the user doesn't provide one. So far I've been doing something like:
template<typename T>
struct simple_compare{
bool operator()(T const& a, T const& b){
return a > b;
}
};
template<typename T, typename Predicate=simple_compare<T> >
bool compare(T a, T b, Predicate pred) {
return pred(a, b);
}
Can this be done using template metaprogramming in C++ instead of having a struct with an overloaded () operator?

There is no need for template metaprogramming here. You can simply use overloading like shown in the answer by Davide Spataro to provide a version that doesn't take a predicate and just calls the full version with a default predicate. Or you can just use a default argument for your predicate:
template <typename T, typename Predicate = simple_compare<T>>
bool compare(T a, T b, Predicate pred = {}) {
return pred(a, b);
}
If you just want a generic functor that invokes the > operator, then you could also just make the operator () a template instead of the functor type itself and let the exact types to compare be deduced from the call:
struct simple_compare {
template <typename A, typename B>
bool operator()(A const& a, B const& b) const {
return a > b;
}
};
template <typename T, typename Predicate = simple_compare>
bool compare(T a, T b, Predicate pred = {}) {
return pred(a, b);
}
Also, the standard library already provides standard functors for invoking all sorts of operators. So instead of rolling your own, you could just use std::greater<T> or std::greater<void> in your example. Furthermore, I assume there is no real need to require your arguments to be copyable and of the same type:
template <typename A, typename B, typename Predicate = std::greater<void>>
bool compare(A const& a, B const& b, Predicate pred = {}) {
return pred(a, b);
}

You do not need fancy template metaprogramming things.
Simply create two versions of the template function. The one without the custom predicate will simply execute the default one.
Something as the following should works:
auto default_pred = [](const auto a, const auto b) {return a > b;};
auto custom_pred = [](const auto a, const auto b) {return a < b;};
template<typename T, typename Fn >
bool compare2(T a, T b, Fn pred) {
return pred(a, b);
}
template<typename T >
bool compare2(T a, T b) {
return default_pred (a, b);
}
int main(){
cout<<compare2(2, 4)<<endl;
cout<<compare2(10.2d, 4.5d, custom_pred)<<endl;
return 0;
}

Related

C++ std::set metaprograming set of set of set ... nesting

I was trying to implement a n-tuple from scratch starting with the mathematical base ordered-pair
where n-tuple (a,b,c) = ordered_pair(a,ordered_pair(b,c)) and ordered pair is a set representation
ie. ordered_pair(a,b) = set{{a},{a,b}}
here is the code for ordered_pair
#include <iostream>
#include <set>
#include <boost/variant.hpp>
using namespace std;
template <typename T, typename U, typename Z>
class orderd_pair{
//typedef boost::variant<int,std::string,double> cell;
private:
set<set<Z>> opair;
set<T> first;
set<U> second;
public:
set<set<Z>> Orderd_pair(T first_element, U second_element){
first.insert(first_element);
second.insert(first_element);
second.insert(second_element);
opair.insert(first);
opair.insert(second);
return opair;
}
//TO DO void print_elements(std::set<std::set<cell>> opair);*/
};
the problem is when trying to implement tuple set of each ordered_pair must be nested ie
for three element tuple set{{a},{a,{{b},{b,c}}}} and for more elements it will be nested even more making it hard to work with, how can I solve this??
also I have used boost::variant to support int,std::string and double data types.
You will quickly find that you can't put a std::set<T> into the same container as a std::set<U> if T is different to U. So you are likely to end up with
struct any_less {
bool operator()(const std::any & lhs, const std::any & rhs) {
return type_index(lhs.type()) < type_index(rhs.type());
}
}
using ordered_pair = std::set<std::set<std::any, any_less>>;
Codifying your recurrence relation.
template <typename A, typename B>
ordered_pair make_ordered_pair(A a, B b) {
return { { a }, { a, b } };
}
template <typename A, typename B, typename C, typename... Rest>
ordered_pair make_ordered_pair(A a, B b, C c, Rest... rest) {
return { { a }, { a, make_ordered_pair(b, c, rest...) } };
}
But C++ has a much better type for ordered pairs: std::pair. It also has a much better type for tuples: std::tuple.

Enabling automatic deduction of template argument type based on that argument's default value

Here's what I want to do:
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp =
[](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;})
{
}
int main()
{
std::vector<int> a{1, 2};
f(a);
return 0;
}
But it doesn't work: could not deduce template argument for 'ComparatorType'.
Using a proxy function instead of an actual default argument value works, but seems overly verbose, isn't there a better way? Not to mention it's not the same since now I can't just substitute the default comparator with my own without changing the function name in the client code.
#include <vector>
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f2(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
int main()
{
std::vector<int> a{1, 2};
f2(a);
return 0;
}
without changing the function name in the client code.
You can overload function templates just fine. There is no need to use a different name.
template <class ContainerType, typename ComparatorType>
void f(
ContainerType c1,
ComparatorType comp)
{
}
template <class ContainerType>
void f(ContainerType c)
{
f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}
You can't make a default function argument contribute to template argument deduction. It's not allowed because it raises some difficult to resolve questions in the deduction process.
Template deduction is performed before default arguments are considered. Also, lambdas are not allowed to appear in unevaluated operands.
You can first assign the default function to a variable. Then you can spell out its type. For example:
auto default_functor = [](int x){ return x > 0; };
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}
Now you can use the function as usual:
bool even(int x)
{
return x % 2 == 0;
}
struct Odd {
bool operator()(int x) const
{
return x % 2 == 1;
}
};
void g()
{
function(1); // use default functor
function(1, even); // use a free function
function(1, Odd{}); // use a function object
function(1, [](int x){ return x < 0; }); // use another lambda
}
You don't need to explicitly specify the type.
Note: According to #StoryTeller, this can lead to ODR violation if you use it in a header. In that case, you can use a named functor type:
struct Positive {
constexpr bool operator(int x) const
{
return x > 0;
}
};
inline constexpr Positive default_functor{};
template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
return f(x);
}

C++ STL functional equivalents for metaprogramming

Are there constexpr or other compile time equivalents to the STL functional and other libraries for use with metaprogramming? More specifically, I am trying to write some metaprograms that use SFINAE to evaluate some conditional and generate the corresponding types. Example:
template<int A, int B>
enable_if_t<(A < B)> my_func() {// do something
}
template<int A, int B>
enable_if_t<!(A < B)> my_func() {// do nothing
}
Ideally I would like the user to be able to pass in a comparator (like std::less<int>), rather than hard coding it to <. So something like:
template<int A, int B, class comp = std::less<int>>
enable_if_t<comp(A, B)> my_func() {// do something
}
template<int A, int B, class comp = std::less<int>>
enable_if_t<comp(A, B)> my_func() {// do nothing
}
However since the functional objects are not constant expressions, they are not getting evaluated at compile time and so this does not work. What would be the right way to implement something like this?
std::less<int>(int, int) is not a constructor for std::less. The only constructor for std::less is () (I prefer using {}, because it makes it clear I'm constructing something).
Since C++14 it has a constexpr operator() that (if < on the types involved is constexpr) can be evaluated at compile time.
Thus:
template<int A, int B, class comp = std::less<int>>
enable_if_t<comp{}(A, B)> my_func() {// do something
}
template<int A, int B, class comp = std::less<int>>
enable_if_t<!comp{}(A, B)> my_func() {// do nothing
}
should work.
In C++11
namespace notstd {
template<class T=void>
struct less {
constexpr bool operator()(T const& lhs, T const& rhs)const{
return lhs<rhs;
}
};
template<>
struct less<void> {
template<class T, class U>
constexpr bool operator()(T const& lhs, U const& rhs)const{
return lhs<rhs;
}
// maybe also add this:
//struct is_transparent {};
}
}
(assuming your < on your system is a total order on pointers) should work (replacing std::less<T> with notstd::less<T>).

implement my own myless

I am trying to understad how std::less is implemented so I can say
template <typename T>
struct myless
{
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs < rhs;
}
};
template <typename A, typename B, typename U = myless> // std::less works
bool f(A a, B b, U u = U())
{
return u(a, b);
}
int main()
{
std::cout << std::boolalpha;
std::cout << f("AB/CD", "CD/AB") << '\n';
std::cout << f(100, 10) << '\n';
}
This doesn't work. Any suggestions?
There is a typo in f("AB/CD", "CD/AB",) (comma).
It should be typename U = myless<A> because myless is not in the std namespace.
Also the parameters should probably be passed by reference: bool f(const A& a, const B& b, const U& u = U()).
std::less needs both operands to be of the same type (logically), and myless is also defined like that. So using myless<A> for U would make it convert the B object to A for the comparing (by creating a temporary using its copy-constructor).
Since C++14, there is also the specialization std::less<void> where the operand can have different types, and a return type that is not bool. It maps one-to-one to what the operator< does. See http://en.cppreference.com/w/cpp/utility/functional/less_void .
Corrected version of the code:
#include <iostream>
template <typename T>
struct myless
{
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs < rhs;
}
};
template <typename A, typename B, typename U = myless<A>>
bool f(const A& a, const B& b, const U& u = U())
{
return u(a, b);
}
int main()
{
std::cout << std::boolalpha;
std::cout << f("AB/CD", "CD/AB") << '\n';
std::cout << f(100, 10) << '\n';
}
For a version that can have different types, and non-bool return type:
struct myless2 {
template<class T, class U>
constexpr auto operator()(const T& t, const U& u) const -> decltype(t < u) {
return t < u;
}
};
std::less<void> seems to also support r-value references, for when the operator< is defined like that (probably doing something else than comparation then.)
Your myless template takes a single type but your f function takes two types (i.e., they might be different types). It's possible to support this but it's more involved. Did you intend to do the following instead?
template<typename T, typename U = myless<T>>
bool f(T a, T b, U u = U())
{
return u(a, b);
}
Edit
As #vscoftco pointed out supporting different types may have been an intended use case. If different types were to be explicitly supported then I would have implemented it like this.
template<typename A, typename B, typename U = myless<typename std::common_type<A, B>::type>>
bool f(A a, B b, U u = U())
{
return u(a, b);
}
It also appears this solution is SFINAE compatible (C++17), http://en.cppreference.com/w/cpp/types/common_type.
If sizeof...(T) is zero or if there is no common type, the member type is not defined (std::common_type is SFINAE-friendly)

Pass pointer-to-template-function as function argument?

Say I want a C++ function to perform arithmetic on two inputs, treating them as a given type:
pseudo:
function(var X,var Y,function OP)
{
if(something)
return OP<int>(X,Y);
else if(something else)
return OP<double>(X,Y);
else
return OP<string>(X,Y);
}
functions that fit OP might be like:
template <class T> add(var X,var Y)
{
return (T)X + (T)Y; //X, Y are of a type with overloaded operators
}
So, the question is what would the signature for function look like? If the operator functions are non-templated I can do it, but I get confused with this extra complexity.
Template functions cannot be passed as template arguments. You have to manually deduce template arguments for this function before you pass it to another template function. For example, you have function
T sum(T a, T b)
{
return a + b;
}
You want to pass it to callFunc:
template<typename F, typename T>
T callFunc(T a, T b, F f)
{
return f(a, b);
}
You can't simply write
int a = callFunc(1, 2, sum);
You have to write
int a = callFunc(1, 2, sum<int>);
To be able to pass sum without writing int, you have to write a functor - struct or class with operator() that will call your template function. Then you can pass this functor as template argument. Here is an example.
template<class T>
T sum(T a, T b)
{
return a + b;
}
template<class T>
struct Summator
{
T operator()(T a, T b)
{
return sum<T>(a, b);
}
};
template<template<typename> class TFunctor, class T>
T doSomething(T a, T b)
{
return TFunctor<T>()(a, b);
//Equivalent to this:
//TFunctor<T> functor;
//return functor(a, b);
}
int main()
{
int n1 = 1;
int n2 = 2;
int n3 = doSomething<Summator>(n1, n2); //n3 == 3
return 0;
}
Are you looking for this?
template<class T> T add(T X, T Y)
{
return X + Y;
}
Or are you looking for something that calls something like add?
template<class T, class F>
T Apply(T x, T y, F f)
{
return f( x, y );
}
Called via:
int x = Apply( 2, 4, add<int> );
I'm a bit confused … why the type differentiation in your pseudo-code?
C++ templates allow full type deduction on templates:
template <typename T, typename F>
T function(T x, T y, F op) {
return op(x, y);
}
Here, F fits anything (especially functions) that may be called with the () function call syntax and accepting exactly two arguments of type T (or implicitly convertible to it).
I use lambdas for this.
auto add = [](const auto& lhs, const auto& rhs) {
static_assert(std::is_arithmetic<typename std::decay<decltype(lhs)>::type>::value,
"Needs to be arithmetic.");
static_assert(std::is_arithmetic<typename std::decay<decltype(rhs)>::type>::value,
"Needs to be arithmetic.");
return lhs + rhs;
};
template<typename LHS, typename RHS, typename FUNC
, typename OUT = typename std::result_of<FUNC(LHS, RHS)>::type>
constexpr OUT do_arithmetic(LHS lhs, RHS rhs, FUNC func) {
return func(lhs, rhs);
}
constexpr auto t = do_arithmetic(40, 2, add);
static_assert(t == 42, "Wrong answer!");
static_assert(std::is_same<std::decay<decltype(t)>::type, int>::value,
"Should be int.");
template <class OP> void function(OP op)
{
// call with int
op(1, 2);
// or with double
op(1.2, 2.3);
// call with explicit template argument
op.template operator()<int>(1, 2);
op.template operator()<string>("one", "two");
}
struct Add
{
template <class T> T operator ()(T a, T b)
{
return a + b;
}
};
function(Add());
// or call with C++14 lambda
function([](auto a, auto b) { return a + b; });
I think you're looking for the Strategy Pattern.
I'm not sure what this var thing in your question means. It's certainly not a valid C++ keyword, so I assume it's a type akin to boost:any. Also, the function is missing a result type. I added another var, whatever that might be. The your solution could look like this:
template< template<typename> class Func >
var function(var X, var Y, Func OP)
{
if(something)
return OP<int>(X,Y);
else if(something else)
return OP<double>(X,Y);
else
return OP<string>(X,Y);
}
The funny template argument is a template itself, hence its name "template template argument". You pass in the name of a template, not an instance. That is, you pass std::plus, not std::plus<int>:
return function( a, b, std::plus );