I want to have a function that evaluates 2 bool vars (like a truth table).
For example:
Since
T | F : T
then
myfunc('t', 'f', ||); /*defined as: bool myfunc(char lv, char rv, ????)*/
should return true;.
How can I pass the third parameter?
(I know is possible to pass it as a char* but then I will have to have another table to compare operator string and then do the operation which is something I would like to avoid)
Is it possible to pass an operator like ^ (XOR) or || (OR) or && (AND), etc to a function/method?
Declare:
template<class Func> bool myfunc(char lv, char rv, Func func);
Or if you need to link it separately:
bool myfunc(char lv, char rv, std::function<bool(bool,bool)> func);
Then you can call:
myfunc('t', 'f', std::logical_or<bool>());
#ybungalobill posted a C++ correct answer and you should stick to it. If you want to pass the operators, functions will not work, but macros would do the work:
#define MYFUNC(lv, rv, op) ....
// Call it like this
MYFUNC('t', 'f', ||);
Be careful, macros are evil.
What you can do is define proxy operators that return specific types.
namespace detail {
class or {
bool operator()(bool a, bool b) {
return a || b;
}
};
class and {
bool operator()(bool a, bool b) {
return a && b;
}
};
// etc
class X {
or operator||(X x) const { return or(); }
and operator&&(X x) const { return and(); }
};
};
const detail::X boolean;
template<typename T> bool myfunc(bool a, bool b, T t) {
return t(a, b);
}
// and/or
bool myfunc(bool a, bool b, std::function<bool (bool, bool)> func) {
return func(a, b);
}
// example
bool result = myfunc(a, b, boolean || boolean);
You can if desperate chain this effect using templates to pass complex logical expressions.
Also, the XOR operator is bitwise, not logical- although the difference is realistically nothing.
However, there's a reason that lambdas exist in C++0x and it's because this kind of thing flat out sucks in C++03.
In modern C++ can pass any operator by using lambdas.
Update 1: the proposed solution introduces small improvement which is suggested by #HolyBlackCat
#include <iostream>
template<class T, class F> void reveal_or(T a, T b, F f)
{
// using as function(a, b) instead of expression a || b is the same thing
if ( f(a, b) )
std::cout << a << " is || " << b << std::endl;
else
std::cout << a << " is not || " << b << std::endl;
}
template<class T> void reveal_or(T a, T b)
{
// reuse the already defined ||
reveal_or(a, b, [](T t1, T t2) {return t1 || t2; });
}
Don't bother how to pass parameter if || operator is defined
int main ()
{
reveal_or('1', 'a');
return 0;
}
Passing explicitly as parameter. We can pass anything, including including any exotic nonsense
int main ()
{
//same as above:
reveal_or('1', 'a', [](char t1, char t2) { return t1 || t2; });
//opposite of above
reveal_or('1', 'a', [](char t1, char t2) { return !( t1 || t2; ) });
return 0;
}
It's hard to be realized. In C++, function parameter need an memroy address to find its object, but operator is decided in compile time. Operator won't be a object. So you can think about MACRO to finish your task.
Related
In a project I'm working on I have a templated function similar to this where all of the arguments should be of type T
#include <iostream>
template<typename T> bool aWithinBOfC(T a, T b, T c)
{
return std::abs(a - c) < b;
}
the issue I'm having is it won't compile if all of the arguments are not of the same type but it seems reasonable that it should implicitly cast similar types to the one with the highest resolution before evaluation. Is there any way to get a call like this to be valid?
int main()
{
double a{1.2};
double b{1.4};
float c{0.1f};
std::cout << aWithinBOfC(a, b, c) << std::endl;
}
Something along these lines, perhaps:
template<typename T>
bool aWithinBOfCImpl(T a, T b, T c) {
/* actual implemenattion */
}
template <typename ... Args>
auto aWithinBOfC(Args... args) {
return aWithinBOfCImpl<std::common_type_t<Args...>>(args...);
}
Demo
You don’t need implicit conversions at the call site. The compiler will implicitly convert the types to the largest one in the expression in the return statement.
template <class T, class U, class V>
bool aWithinBOfC(T a, U b, V c) {
return std::abs(a - c) < b;
}
Here is a definition of a Result class that aims to simulate the logic of the Either monad from Haskell (Left is Failure; Right is Success).
#include <string>
#include <functional>
#include <iostream>
template <typename S, typename F>
class result
{
private:
S succ;
F fail;
bool pick;
public:
/// Chain results of two computations.
template <typename T>
result<T,F> operator&&(result<T,F> _res) {
if (pick == true) {
return _res;
} else {
return failure(fail);
}
}
/// Chain two computations.
template <typename T>
result<T,F> operator>>=(std::function<result<T,F>(S)> func) {
if (pick == true) {
return func(succ);
} else {
return failure(fail);
}
}
/// Create a result that represents success.
static result success(S _succ) {
result res;
res.succ = _succ;
res.pick = true;
return res;
}
/// Create a result that represents failure.
static result failure(F _fail) {
result res;
res.fail = _fail;
res.pick = false;
return res;
}
};
When trying to compose two results using the && operator, all is well:
int
main(int argc, char* argv[])
{
// Works!
auto res1 = result<int, std::string>::success(2);
auto res2 = result<int, std::string>::success(3);
auto res3 = res1 && res2;
}
But when attempting to chain computations on top of the result, a compilation error appears:
result<int, std::string>
triple(int val)
{
if (val < 100) {
return result<int, std::string>::success(val * 3);
} else {
return result<int, std::string>::failure("can't go over 100!");
}
}
int
main(int argc, char* argv[])
{
// Does not compile!
auto res4 = result<int, std::string>::success(2);
auto res5a = res4 >>= triple;
auto res5b = res4 >>= triple >>= triple;
}
The error from clang++ is as follows:
minimal.cpp:82:21: error: no viable overloaded '>>='
auto res5a = res4 >>= triple;
~~~~ ^ ~~~~~~
minimal.cpp:26:17: note: candidate template ignored: could not match
'function<result<type-parameter-0-0, std::__1::basic_string<char,
std::__1::char_traits<char>, std::__1::allocator<char> > > (int)>' against
'result<int, std::__1::basic_string<char, std::__1::char_traits<char>,
std::__1::allocator<char> > > (*)(int)'
result<T,F> operator>>=(std::function<result<T,F>(S)> func) {
^
minimal.cpp:83:32: error: invalid operands to binary expression ('result<int,
std::string> (int)' and 'result<int, std::string> (*)(int)')
auto res5b = res4 >>= triple >>= triple;
Any idea as to how to fix this issue?
This works
auto f = std::function< result<int, std::string>(int)>(triple);
auto res5a = res4 >>= f;
I cannot give a good concise explanation, only that much: Type deduction does not take into acount conversions and triple is a result<int,std::string>()(int) not a std::function.
You dont have to use std::function but you can accept any callable with something like:
template <typename G>
auto operator>>=(G func) -> decltype(func(std::declval<S>())) {
if (pick == true) {
return func(succ);
} else {
return failure(fail);
}
}
Live Demo
Note that std::function comes with some overhead. It uses type erasure to be able to store all kinds of callables. When you want to pass only one callable there is no need to pay that cost.
For the second line #Yksisarvinen's comment already summarizes it. For the sake of completeness I simply quote it here
auto res5b = res4 >>= triple >>= triple; will not work without
additional operator for two function pointers or an explicit brackets
around res4 >>= triple, because operator >>= is a right-to-left one.
It will try first to apply >>= on triple and triple.
PS: I dont know Either and your code is a bit more functional style than what I am used to, maybe you can get similar out of std::conditional?
So, in C++, a std::function is not the base class of anything of interest. You cannot deduce the type of a std::function from a function or a lambda.
So your:
/// Chain two computations.
template <typename T>
result<T,F> operator>>=(std::function<result<T,F>(S)> func)
will only deduce when passed an actual std::function.
Now, what you really mean is "something that takes an S and returns a result<T,F> for some type T".
This isn't how you say it in C++.
As noted, >>= is right-associative. I might propose ->* instead, which is left-to-right.
Second, your failure static function won't work right, as it returns the wrong type often.
template<class F>
struct failure {
F t;
};
template<class F>
failure(F)->failure{F};
then add a constructor taking a failure<F>.
/// Chain two computations.
template<class Self, class Rhs,
std::enable_if_t<std::is_same<result, std::decay_t<Self>>{}, bool> = true
>
auto operator->*( Self&& self, Rhs&& rhs )
-> decltype( std::declval<Rhs>()( std::declval<Self>().succ ) )
{
if (self.pick == true) {
return std::forward<Rhs>(rhs)(std::forward<Self>(self).succ);
} else {
return failure{std::forward<Self>(self).fail};
}
}
I am now carefully paying attention to r/lvalue ness of the types involved, and will move if possible.
template<class F>
struct failure {
F f;
};
template<class F>
failure(F&&)->failure<std::decay_t<F>>;
template<class S>
struct success {
S s;
};
template<class S>
success(S&&)->success<std::decay_t<S>>;
template <class S, class F>
class result
{
private:
std::variant<S, F> state;
public:
bool successful() const {
return state.index() == 0;
}
template<class Self,
std::enable_if_t< std::is_same<result, std::decay_t<Self>>{}, bool> = true
>
friend decltype(auto) s( Self&& self ) {
return std::get<0>(std::forward<Self>(self).state);
}
template<class Self,
std::enable_if_t< std::is_same<result, std::decay_t<Self>>{}, bool> = true
>
friend decltype(auto) f( Self&& self ) {
return std::get<1>(std::forward<Self>(self).state);
}
/// Chain results of two computations.
template<class Self, class Rhs,
std::enable_if_t< std::is_same<result, std::decay_t<Self>>{}, bool> = true
>
friend std::decay_t<Rhs> operator&&(Self&& self, Rhs&& rhs) {
if (self.successful()) {
return success{s(std::forward<Rhs>(rhs))};
} else {
return failure{f(std::forward<Self>(self))};
}
}
/// Chain two computations.
template<class Self, class Rhs,
std::enable_if_t< std::is_same<result, std::decay_t<Self>>{}, bool> = true
>
friend auto operator->*(Self&&self, Rhs&& rhs)
-> decltype( std::declval<Rhs>()( s( std::declval<Self>() ) ) )
{
if (self.successful()) {
return std::forward<Rhs>(rhs)(s(std::forward<Self>(self)));
} else {
return failure{f(std::forward<Self>(self))};
}
}
template<class T>
result( success<T> s ):
state(std::forward<T>(s.s))
{}
template<class T>
result( failure<T> f ):
state(std::forward<T>(f.f))
{}
explicit operator bool() const { return successful(); }
};
live example.
Uses c++17.
Implementing Result cleanly and efficently
C++ can represent a Result type just as cleanly and efficiently as haskell. Like Haskell, C++ has true sum types, and we can encapsulate the entirety of their functionality with a tagged union. In addition, by taking advantage of implicit construction, we can represent Success and Failure as types instead of static member functions (this makes things a lot cleaner).
Defining Success and Failure
These are really simple. They're just wrapper classes, so we can implement them as aggregates. In addition, using C++17's template deduction guides, we won't have to specify the template parameters for Failure and Success. Instead, we'll just be able to write Success{10}, or Failure{"Bad arg"}.
template <class F>
class Failure {
public:
F value;
};
template<class F>
Failure(F) -> Failure<F>;
template <class S>
class Success {
public:
S value;
// This allows chaining from an initial Success
template<class Fun>
auto operator>>(Fun&& func) const {
return func(value);
}
};
template <class S>
Success(S) -> Success<S>;
Defining Result
Result is a sum type. That means it can be either a success or a failure, but not both. We can represent this with a union, which we'll tag with a was_success bool.
template < class S, class F>
class Result {
union {
Success<S> success;
Failure<F> failure;
};
bool was_success = false; // We set this just to ensure it's in a well-defined state
public:
// Result overloads 1 through 4
Result(Success<S> const& s) : success(s), was_success(true) {}
Result(Failure<F> const& f) : failure(f), was_success(false) {}
Result(Success<S>&& s) : success(std::move(s)), was_success(true) {}
Result(Failure<F>&& f) : failure(std::move(f)), was_success(false) {}
// Result overloads 5 through 8
template<class S2>
Result(Success<S2> const& s) : success{S(s.value)}, was_success(true) {}
template<class F2>
Result(Failure<F2> const& f) : failure{F(f.value)}, was_success(false) {}
template<class S2>
Result(Success<S2>&& s) : success{S(std::move(s.value))}, was_success(true) {}
template<class F2>
Result(Failure<F2>&& f) : failure{F(std::move(f.value))}, was_success(false) {}
// Result overloads 9 through 10
Result(Result const&) = default;
Result(Result&&) = default;
template<class S2>
Result<S2, F> operator&&(Result<S2, F> const& res) {
if(was_success) {
return res;
} else {
return Failure{failure};
}
}
template<class Fun, class Ret = decltype(valueOf<Fun>()(success.value))>
auto operator>>(Fun&& func) const
-> Ret
{
if(was_success) {
return func(success.value);
} else {
return failure;
}
}
~Result() {
if(was_success) {
success.~Success<S>();
} else {
failure.~Failure<F>();
}
}
};
Explaining Result(...)
A result is either constructed from a success or a failure.
Overloads 1 through 4 just handle the basic copy and move construction from Success and Failure objects;
Overloads 5 trhough 8 handle the case where we want to do an implicit conversion (as in the case of a string literal to a std::string.
Overloads 9 and 10 handle move and copy construction of Result.
Explaining operator>>
This is pretty similar to your implementation of operator>>=, and i'll explain the reasoning behind my changes.
template<class Fun, class Ret = decltype(valueOf<Fun>()(success.value))>
auto operator>>(Fun&& func) const
-> Ret
{
if(was_success) {
return func(success.value);
} else {
return failure;
}
}
Why not use std::function? std::function is a type-erasing wrapper. That means that it uses virtual function calls under the hood, which slow things down. By using an unconstrained template, we make it much easier for the compiler to optimize stuff.
Why use >> instead of >>=? I used >> because >>= has weird behavior since it's an assignment operator. The statement a >>= b >>= c is actually a >>= (b >>= c), which is not what we intended.
What does class Ret = decltype(valueOf<Fun>()(success.value)) do? That defines a template parameter which is defaulted to the return type of the function you pass. This enables us to avoid using std::function while also allowing us to use lambdas.
Explaining ~Result()
Because Result contains a union, we have to manually specify how to destruct it. (Classes containing Result won't have to do this - once we specify it inside Result, everything behaves like normal). This is pretty straight-forward. If it contains the Success object, we destroy that one. Otherwise, we destroy the failure one.
// Result class
~Result() {
if(was_success) {
success.~Success<S>();
} else {
failure.~Failure<F>();
}
}
Updating your example for my implementation
Now that we've written a Result class, we can update your definitions of triple and main.
New definition of triple
Pretty straight-forward; we just replaced your success and failure functions with the Success and Failure types.
auto triple(int val) -> Result<int, std::string>
{
if (val < 100) {
return Success{val * 3};
} else {
return Failure{"can't go over 100"};
}
}
New definition of main
I added a print function so we can actually see some output. It's just a lambda. There are two computations done, one for ans and the other for ans2. The one for ans prints 18, because triple doesn't push the number over 100, but the one for ans2 doesn't print anything because it results in a failure.
int main(int argc, char* argv[])
{
auto print = [](auto value) -> Result<decltype(value), std::string> {
std::cout << "Obtained value: " << value << '\n';
return Success{value};
};
auto ans = Success{2} >> triple >> triple >> print;
auto ans2 = Success{2} >> triple >> triple >> triple >> triple >> triple >> print;
}
You can play with the code here!
I would like to apply an overloaded function to all elements of a struct like so: (The code below will not compile)
#include <iostream>
typedef struct {
float float_val;
int int_val;
} NodeStatus;
template<typename T>
void ApplyToFields(NodeStatus *ns1, NodeStatus *ns2, void (*func)(T, T)) {
func(ns1->float_val, ns2->float_val);
func(ns1->int_val, ns2->int_val);
}
template<typename T>
void add_print(T a, T b) {
std::cout << b + a << std::endl;
}
template<typename T>
void sub_print(T a, T b) {
std::cout << b - a << std::endl;
}
int main() {
NodeStatus ns1, ns2;
ns1.float_val = 2.3;
ns2.float_val = 25.3;
ns1.int_val = 2;
ns2.int_val = 20;
ApplyToFields(&ns1, &ns2, add_print);
ApplyToFields(&ns1, &ns2, sub_print);
}
I am new to C++ coming from C. After some research I realize that passing a function pointer is probably not the correct way to do this in C++. I am interested in the best way to accomplish the same purpose as opposed to the literal question I posed which may be impossible. Solutions adhering to C++03 would be ideal. Thanks!
You can create a function object wrapping your function template (or replacing it):
struct add_printer {
template<typename T>
void operator()(T a, T b) const {
add_print(a, b);
}
};
And then use it like this:
ApplyToFields(&ns1, &ns2, add_printer());
This will delay overload resolution until add_printer's operator() is actually instantiated when it is used in ApplyToFields.
In C++14, you could use a polymorphic lambda:
[](auto a, auto b) { add_print(a, b); }
which, unlike the function object, can be defined almost anywhere, not just at namespace scope.
With your code, you have to specify which overload you want:
ApplyToFields(&ns1, &ns2, add_print<float>);
ApplyToFields(&ns1, &ns2, sub_print<int>);
or
ApplyToFields<float>(&ns1, &ns2, add_print);
ApplyToFields<int>(&ns1, &ns2, sub_print);
Demo
That you want is a generic functor
template<typename F>
void ApplyToFields(const NodeStatus &ns1, const NodeStatus &ns2, F func) {
func(ns1.float_val, ns2.float_val);
func(ns1.int_val, ns2.int_val);
}
struct add_print
{
template<typename T>
void operator() (T a, T b) {
std::cout << b + a << std::endl;
}
};
Demo
What is the correct way to perform == and != operators in template classes?
Assume this code:
template<typename T>
class C {
T x, y;
public:
C(T a, T b) : x(a), y(b) {}
bool cmp() {
return x == y;
}
};
int main()
{
// OK
C<int> i(1,2);
i.cmp();
// not OK
C<double> d(1.0, 2.0);
d.cmp();
return 0;
}
If you build it with g++ -Wfloat-equal, you'll get
warning: comparing floating point with == or != is unsafe
[-Wfloat-equal]
because you can't simply compare float variables.
Update
I've solved the problem using type_traits and enable_if like this (thanks #Andrew and #OMGtechy):
#include <type_traits>
#include <limits>
#include <cmath>
#include <iostream>
using namespace std;
template <typename IntegralType>
typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type
equal(const IntegralType& a, const IntegralType& b) {
return a == b;
}
template <typename FloatingType>
typename std::enable_if<std::is_floating_point<FloatingType>::value, bool>::type
equal(const FloatingType& a, const FloatingType& b) {
return std::fabs(a-b) < std::numeric_limits<FloatingType>::epsilon();
}
template<typename T>
class C {
T x, y;
public:
C(T a, T b) : x(a), y(b) {}
bool cmp() {
return equal(x, y);
}
};
int main()
{
// OK
C<int> i(1,2);
cout << i.cmp() << endl;
// not OK
C<double> d(1.0, 1.0);
cout << d.cmp() << endl;
return 0;
}
This question seems to be asking two things:
How can I do floating point comparisons without using operator==, and
how can I modify the behaviour of a template depending on the type passed to it.
One answer to the second question is to use type traits. The code below demonstrates this for your situation, providing a comparison_traits for general types (using ==) and a specialisation for doubles, using a tolerance (which answers the first question, too).
#include <cmath>
template <typename T> struct comparison_traits {
bool equal(const T& a, const T& b) {
return a == b;
}
// etc.
};
template<> struct comparison_traits<double> {
bool equal(const double& a, const double& b) {
return fabs(a - b) < 1e-15; // or whatever...
}
};
template <typename T>
class C {
T x, y;
public:
C(const T& a, const T& b) : x(a), y(b) {}
bool cmp() {
return comparison_traits<T>::equal(x, y);
}
};
int main() {
// OK
C<int> i(1, 2);
i.cmp();
// Now OK too...
C<double> d(1.0, 2.0);
d.cmp();
return 0;
}
Other options include:
Providing a template parameter that allows you to specify a comparison function, defaulting to std::equal_to
Specialising your template for double, so that you can write a different implementation of cmp()
It depends how it will be used. Comparing floats properly depends on the context.
I would recommend what #Niall says: add a comparator template parameter, defaulting to std::equal_to. This will allow callers to control how values are compared. See for example the docs on std::sort to see how a comparator parameter is used. The downside to this is that it's the caller's responsibility to account for comparing floats. If they forget, then they'll get the compiler warning you see.
Another option is template class specialization. Make a specialization for your class to deal specifically with float or double types, and compare them differently using whatever logic you prefer. Probably not the best solution though. The benefit to this is that callers no longer need to remember to specify a comparator.
If you ask why you get this warning:
here some example:
double a,b;
a=10.0/13.0;
b = a/3;
b*=3;
std::cout<<"a="<<a<<std::endl;
std::cout<<"b="<<b<<std::endl;
if(a!=b){
std::cout<<"NOT equal!!"<<std::endl;
std::cout<<"a-b="<<a-b<<std::endl;
}
else
std::cout<<"equal"<<std::endl;
if you'll do the math a and b are clearly equal.
but this is the output I've got:
a=0.769231
b=0.769231
NOT equal!!
a-b=-1.11022e-016
because it is not so accurate, a proper comparison for double should define some tolerancy:
for example(tolerancy may change according needs):
int compare(double a, double b)
{
double tolerancy = 0.000001;
if (abs(a-b) < tolerancy) return 0;
else if (a>b) return 1;
else /*if (a<b)*/ return -1;
}
and if I use this compare i get:
a=0.769231
b=0.769231
equal
I don't know if it's possible but I want to do stuff like
int someval = 1;
if({1,2,3,4}_v.contains(someval ))
but when I try to define literal as:
std::vector<int> operator"" _v ( std::initializer_list<int> t )
{
return std::vector<int> (t);
}
to accept initializer list of ints I get
error: 'std::vector<int> operator"" _v(std::initializer_list<int> t)' has invalid argument list
Is there a way to do this? What I really want is to finally be rid of stuff like
if(value == 1 || value ==2 || value == 3 ...
Having to write stuff like this is really annoying, because you'd expect syntax to be
if value in (value1, value2 ...)
or something similar.
How about this:
#include <initializer_list>
template <typename T>
bool contains(std::initializer_list<T> const & il, T const & x)
{
for (auto const & z : il) { if (z == x) return true; }
return false;
}
Usage:
bool b = contains({1, 2, 3}, 5); // false
you'd expect syntax to be
if value in (value1, value2 ...)
or something similar.
If you're willing to add one extra character, try this syntax:
#include <algorithm>
#include <iostream>
#include <array>
template <typename T0, typename T1, std::size_t N>
bool operator *(const T0& lhs, const std::array<T1, N>& rhs) {
return std::find(begin(rhs), end(rhs), lhs) != end(rhs);
}
template<class T0, class...T> std::array<T0, 1+sizeof...(T)> in(T0 arg0, T...args) {
return {{arg0, args...}};
}
int main () {
if( 2 *in(1,2,3) ) { std::cout << "Hello\n"; }
if( 4 *in(5,6,7,8) ) { std::cout << "Goodbye\n"; }
}
§13.5.8/3 says:
The declaration of a literal operator shall have a
parameter-declaration-clause equivalent to one of the following:
const char*
unsigned long long int
long double
char
wchar_t
char16_t
char32_t
const char*, std::size_t
const wchar_t*, std::size_t
const char16_t*, std::size_t
const char32_t*, std::size_t
So it looks like you can't have a parameter of initializer_list type.
I can only think of the obvious as an alternative; if you don't mind typing a little more you can do something like
std::vector<int> v(std::initializer_list<int> l) {
return { l };
}
int someval = 1;
if(v({1,2,3,4}).contains(someval))
Alternatively you could get wacky and write an operator overload for initializer_list (haven't tested though):
bool operator<=(std::intializer_list<int> l, int value) {
return std::find(std::begin(l), std::end(l), value) != std::end(l);
}
And
if ({1, 2, 3, 4} <= 3)
should work...
Actually nevermind, it doesn't. You'll have to go with a normal function.