What does it mean to overload operator bool with two parameters? - c++

In an assignment I'm told to implement bool operator()(const T&, const T&) for some class. Overloading bool operator is meant to allow the object to be implicitly cast to bool. What does it mean to overload it with two parameters? How are these parameters passed on the calling side? How is this used?

That is not "operator bool", but operator(), with two T arguments, returning a bool. In other words, it is a binary predicate. You can use it like this:
struct Foo
{
bool operator()(const T&, const T&); // should probably be const
};
...
Foo f;
T t1, t2;
bool b = f(t1, t2);

You confuse operator bool with operator() with return type bool. The assignment is about the latter.

Related

C++ functors, any effective aproach?

In my C++ code I wrote two functors that take to arguments one returns the sum and the other returns the subtract so I could use them as arguments to functions. like this:
template<class T>
class AddValues{
public:
T operator()(const T &value1, const T &value2) {
return value1 + value2;
}
};
template<class T>
class SubstractValues{
public:
T operator()(const T &value1, const T &value2) {
return value1 - value2;
}
};
But now I am looking to write like 6 functors that each one of them takes two arguments and returns true/false wither the first value is <,<=,>,>=,==,!= than the other.
Is there a clearer way to do that rather than defining 6 classes?
I'm working with C++11
Note: This post is a refinement of my comments to the original post.
First, you should be aware that the STL already defines a set of functors. See https://en.cppreference.com/w/cpp/header/functional under Comparators for <,<=,>,>=,==,!=, and Arithmetic operations for +,- (which you have redefined). It is good practice to know the STL and how to use it.
How to use them
Functors are objects like any other object and are to be used with value semantics. For a functional look, they define the function operator (operator()) and can be called () on the object directly.
std::less is_less;
bool is_0_less_than_0 = is_less(0,1); // Calls bool operator()(int, int) and evaluates to true
The functors are usually used in combination with the algorithms. For a not so pretty use case to compare two arrays of integers:
std::array<int,4> low_numbers = {1,2,3,4};
std::array<int,4> high_numbers = {5,6,7,8};
std::array<bool,4> is_number_greater;
// compares low_numbers and high_numbers element wise and stores result in is_number_greater.
std::transform(low_numbers.begin(),
low_numbers_low.end(),
high_numbers.begin(),
is_number_greater.begin(),
std::greater{});
How to write your own functors
So you have already (functionality wise) redefined std::plus (as AddValues) and std::minus (as SubtractValues). Note that I say functionality wise, since it is more flexible to only templatize the function operator:
struct AddValues{
template<class T>
T operator()(const T &value1, const T &value2) {
return value1 + value2;
}
};
And as the member method operator() does not modify any members of AddValues, it should be marked const:
struct AddValues{
template<class T>
T operator()(const T &value1, const T &value2) const {
return value1 + value2;
}
};
Then you do not need to specify the type when instantiating the object. Compare template class:
AddValues<int> add_values; // templated type has to be explicitly written.
add_values(1,2); //=3
with templated method:
AddValues add_values;
add_values(1,2); //=3, types deduced when calling method.
.
Anyway, you would have to do the same for <,<=,>,>=,==,!=, since you need a wrapper around each operator. The difference would only be that now you return booleans instead of a type.
struct MyLess
{
template<typename T>
bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; }
};

Could removing "using namespace std::rel_ops" change behavior?

I recently found that a large project has a "using namespace std::rel_ops;" in a frequently included header file, and in the global namespace. Ouch.
Specifically, it caused an issue because these two function template declarations are ambiguous:
namespace std::rel_ops {
template <class T>
bool operator!=(const T&, const T&);
}
namespace std {
template <class... TTypes, class... UTypes>
constexpr bool operator!=(const tuple<TTypes...>&, const tuple<UTypes...>&);
}
so my attempt to use an expression similar to std::tie(a.m1, a.m2, a.m3) != std::tie(b.m1, b.m2, b.m3) was ill-formed.
So the plan is to delete the using namespace std::rel_ops;, then fix the compiler errors which result, probably by defining more specific comparison operator functions. But I want to also go through the exercise of evaluating whether it would be possible this change could change the meaning of some code hidden somewhere else in this large project, without causing a compiler error.
In what conditions, if any, could two C++ programs with and without a directive using namespace std::rel_ops; differ in behavior, given that neither is ill-formed with a required diagnostic?
I suspect it would require another comparison operator function template which is less specialized than one in std::rel_ops, and which has different effective behavior from the std::rel_ops definition. Both conditions seem quite unlikely in a real project, and even less likely considered together.
There you have one example of this which tells moreless all about this class of errors. Depending on using namespace the program returns different values.
#include <utility>
class Type {
public:
Type(int) {}
};
bool operator==(Type, Type) { return false; }
template<class T , class U>
bool operator!=(const T& lhs, const U& rhs) {
return lhs == rhs;
}
using namespace std::rel_ops;
int main() {
Type bar(1);
Type baz(1);
return bar != baz;
}
Live example
Given a pair of programs with and without using namespace std::rel_ops; which don't violate a rule requiring a diagnostic, a difference in behavior can only be due to overload resolution between a member of rel_ops and another function or function template which is a worse overload in some context with both declarations viable. The overload resolution context could be:
a binary comparison expression, like E1 != E2
an explicit call using an operator-function-id as function name, like operator!=(E1, E2)
a use of operator-function-id or &operator-function-id as an initializer for a pointer to function or reference to function, in one of the contexts listed in [over.over]/1, like static_cast<bool(*)(const std::string&, const std::string&)>
It's actually not that hard for another function or function template specialization to be a worse overload than a member of std::rel_ops. Examples include:
The other function or template specialization requires a user-defined conversion.
class A {};
bool operator==(const A&, const A&);
class B {
public:
B(A);
};
bool operator==(const B&, const B&);
bool operator!=(const B&, const B&);
void test1() {
// With using-directive, selects std::rel_ops::operator!=<A>(const A&, const A&).
// Without, selects operator!=(const B&, const B&).
A{} != A{};
}
class C {
operator int() const;
};
bool operator==(const C&, const C&);
void test2() {
// With using-directive, selects std::rel_ops::operator!=<C>.
// Without, selects the built-in != via converting both arguments to int.
C{} != C{};
The other function or template specialization requires a derived-to-base "Conversion" ([over.best.ics]/6).
class D {};
bool operator==(const D&, const D&);
bool operator!=(const D&, const D&);
class E : public D {};
bool operator==(const E&, const E&);
void test3() {
// With using-directive, selects std::rel_ops::operator!=<E>.
// Without, selects operator!=(const D&, const D&).
E{} != E{};
}
The other function or template specialization has an rvalue reference parameter type.
class F {};
bool operator==(F&&, F&&);
void test4() {
// With using-directive, selects std::rel_ops::operator!=<F>.
// Without, selects operator!=(F&&, F&&).
F{} != F{};
}
The other function is a specialization of a less-specialized function template.
namespace N1 {
class A{};
bool operator==(const A&, const A&);
template <typename T1, typename T2>
bool operator!=(const T1&, const T2&);
}
void test5() {
// With using-directive, selects std::rel_ops::operator!=<N1::A>.
// Without, selects N1::operator!=<N1::A,N1::A>.
N1::A{} != N1::A{};
}
namespace N2 {
class B{};
bool operator==(const B&, const B&);
template <typename T>
bool operator!=(T&, T&);
}
void test6() {
// With using-directive, selects std::rel_ops::operator!=<N2::B>.
// Without, selects operator!=<const N2::B>.
const N2::B b1;
const N2::B b2;
b1 != b2;
}
Other categories and examples are possible, but that more than makes the point.
As far as practical concerns, it's unlikely any of the comparison operator names declared in std::rel_ops would be implemented to give results very different from the rel_ops definition for the same type, given that the related operator< or operator== is also defined. It might make a difference if "invalid" or special values have special treatment, like how for floating point types a <= b is not equivalent to !(b < a) when at least one operand is a NaN value. But the cases involving an implicit conversion to a different type could fairly easily result in different behavior. After a derived-to-base Conversion, any information in derived data members will very likely be ignored. After a converting constructor or conversion function, the comparison is on values of an entirely different type, which supposedly somehow represent the original arguments but might not represent their full functional identities.
(So for the original motivation, I decided it's worth using a static analysis tool to find all the places in the existing code naming a member of std::rel_ops, to help check for unintended changes in meaning not caught by just compiling.)

user defined data type in set in c++

In the first case, code is working fine but I am getting an error in the second code, the only difference is of "const" in the operator overloading of '<', I am not able to figure out why.
Code for both cases are below
1.
class first
{
public:
int y;
bool operator < (first t) const
{
return (y>t.y);
}
};
set<first> f;
2.
class first
{
public:
int y;
bool operator < (first t)
{
return (y>t.y);
}
};
set<first> f;
The default comparator for std::set is std::less<Key> and as we can see on std::less it defines:
constexpr bool operator()( const T& lhs, const T& rhs ) const;
Which accepts const arguments and returns lhs < rhs. This of course doesn't work if lhs < rhs is not valid for const arguments, as it is in your second case because bool operator < (first t) cannot be called.
Writing your own comparator which accepts non-const arguments doesn't seem to work either, so it looks it is a requirement of the ordered container, but further check with the standard is needed to confirm.
std::set, like most other containers in the standard library, uses the requirement Compare for its comparing function. And the Compare requirement enforces constness:
As with any BinaryPredicate, evaluation of that expression is not allowed to call non-const functions through the dereferenced iterators.

STL sort function with comparator

This is a syntax question.
C++ STL sort function:
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
The documentation says that comp can be either a function pointer or an object.
But if you pass a function pointer, what mechanism of C++ allows the function pointer to be used in place of an object i.e. Compare comp?
Why isn't it a compile error?
Given an object with a function call operator,
struct Functor {
bool operator()(const Foo& a, const Foo& b) {
return a < b;
}
};
it is easy to see that the sort function can be instantiated such that the Compare comp parameter accepts a Functor object.
sort(/* other params we don't care about here */, Functor comp);
Fair enough.
Your question is - how can this accept a function pointer? Let's begin by examining what is the type of a function pointer?
Consider the following
bool compare(const Foo& a, const Foo& b);
bool (*func_ptr)(const Foo&, const Foo&) = compare;
The type of a pointer to the function compare, as shown in the second line above, is bool (*)(const Foo&, const Foo&). You can typedef this just as you can any other type:
typedef bool (*func_ptr_type)(const Foo&, const Foo&);
func_ptr_type ptr = compare;
Or equivalently:
using func_ptr_type = bool(*)(const Foo&, const Foo&);
func_ptr_type ptr = compare;
Now, when you provide a function pointer to std::sort, it should be obvious that the type Compare becomes the pointer type, analogous to func_ptr_type above, and the argument looks much the same as the example in the second line:
sort(/* other params we don't care about here */, func_ptr_type comp);
This all works because the sort function is actually a function template. It gets instantiated with different types based on its usage. When it's instantiated with an object, its parameter accepts that object by value (the Compare type is deduced to be the type of the object). When it's instantiated with a function pointer, the Compare type is deduced to be the function pointer type.

SFINAE with boost enable if

I am trying to implement a templated pair class that uses sfinae to distinguish between array and non-array types. So far, I have the following code:
template <typename T>
class pair
{
public:
//default constructors. one for non-array types and one for arrays. These work.
template <typename temp_type = T>
pair(typename boost::disable_if<boost::is_array<temp_type>>::type* ignore = 0)
: first(T())
, second(T())
{}
template <typename temp_type = T>
pair(typename boost::enable_if<boost::is_array<temp_type>>::type* ignore = 0)
{}
//assignment operator attempts for non-array types (not in code at same time.) These don't work.
template<typename temp_type = T>
pair<temp_type>& operator=(pair<typename boost::disable_if<boost::is_array<temp_type>>::type> const& rhs)
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
template<typename temp_type = T>
auto operator=(pair<temp_type> const& rhs) -> pair<typename boost::disable_if<boost::is_array<temp_type>>::type>&
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
T first;
T second;
};
The first attempt at the assignment operator fails with an "illegal use of type void" error. The second compiles, but when I debug, MSVC tells me that "no executable code is associated with that line." I am using the MSVC 12 64 bit compiler.
If you could offer any insight as to what is wrong here, that would be very helpful.
Also, just a few observations I've made about sfinae in c++ (that may be right or wrong):
sfinae requires the member function to be templated but it cannot use the class template type(s) for this purpose. Why?
sfinae can be done by only modifying the template parameters and not the return type or inputs. How, exactly does this work. What's the flexibility of this method?
I know this is long winded and references topics covered in numerous other posts, but I haven't been able to put those explanations together in a way that concisely explains sfinae in c++.
Some posts I've read:
Explain C++ SFINAE to a non-C++ programmer (high level intro)
Select class constructor using enable_if (sfinae for constructors)
Thanks for any help.
EDIT:
I have modified my code based on the comments below and I still can't get this to work as expected (The compiler is not even seeing the source.) It's an interesting situation because the example is completely contrived and the default assignment operator actually works in this scenario. Nevertheless, I don't think the compiler should be overriding my attempt to overload the operator.
I have tried the following 4 methods and none of them seem to be built into the executable:
template<typename temp_type = T>
pair<temp_type>& operator=(pair<typename boost::disable_if<boost::is_array<temp_type>, temp_type>::type> const& rhs)
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
template<typename temp_type = T>
auto operator=(pair<temp_type> const& rhs) -> pair<typename boost::disable_if<boost::is_array<temp_type>, temp_type>::type>&
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
template<typename ret_type = boost::disable_if<boost::is_array<T>, T>::type, typename = void>
pair<ret_type>& operator=(pair<ret_type> const& rhs)
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
template<typename temp_type = T, typename boost::enable_if<boost::is_array<temp_type>, temp_type>::type = 0>
pair<T>& operator=(pair<temp_type> const& rhs)
{
this->first = rhs.first;
this->second = rhs.second;
return *this;
}
Thoughts?
Don't forget, converting assignment can be implemented by template functions, but copy and move assignment operators can't.
A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.
If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted
A user-declared move assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X&&, const X&&, volatile X&&, or const volatile X&&.
and the note
Because a template assignment operator or an assignment operator taking an rvalue reference parameter is never a copy assignment operator, the presence of such an assignment operator does not suppress the implicit declaration of a copy assignment operator. Such assignment operators participate in overload resolution with other assignment operators, including copy assignment operators, and, if selected, will be used to assign an object.
(above quotes found in section 12.8, wording from draft n3936)
Why your attempts fail to work is explained in #BenVoigt 's answer, here is only an alternative solution. You can dispatch the operator= call to an appropriate overload depending on the type your template was instantiated with:
#include <iostream>
#include <boost/type_traits.hpp>
template <typename T>
class pair
{
public:
pair& operator=(pair const& rhs)
{
return assign(rhs, boost::is_array<T>());
}
private:
pair& assign(pair const&, boost::true_type)
{
std::cout << "array" << std::endl;
return *this;
}
pair& assign(pair const&, boost::false_type)
{
std::cout << "not array" << std::endl;
return *this;
}
};
int main()
{
pair<int> a, b;
b = a;
pair<int[]> c, d;
c = d;
}
Output:
not array
array
And you can do the same with constructors, delegating (C++11) the call to another one:
pair() : pair(boost::is_array<T>()) {}
pair(boost::true_type) { /*initialize array pair*/ }
pair(boost::false_type) { /*initialize non-array pair*/ }
Code looks cleaner and you don't have to compete with the compiler on whose operator= better matches the actual argument.
DEMO