In my C++ class we are learning to use function objects and the like, but now we got a code snippet that works on teacher's compiler but not on ours (we use different OS's).
We tested the code snippet below with several compilers (MSVC, clang) and they all reject it, a bit minimized:
#include <functional>
struct Fraction {
Fraction();
Fraction(int z, int n);
Fraction(Fraction&);
// various data members
};
struct FractionComparator {
int operator()(Fraction a, Fraction b) {
return 1;
}
};
int main() {
std::function<int(Fraction, Fraction)> comparator = FractionComparator();
}
We get on clang on macOS:
No viable conversion from 'FractionComparator' to 'function<int (Fraction, Fraction)>'
We already found out that adding a move constructor solves the problem, but we have no idea why this difference exists and why this code doesn't compile on our compilers.
Any ideas?
We use lambda functionas comparator. As usual, comparator should return boolean value, indicating whether the element passed as first argument is considered to go before the second in the specific strict weak orderingit defines. Online demo 2. Modern C++11 solution auto cmp = [](int a, int b) { return ... }; std::set<int, decltype(cmp)> s(cmp);
C++ Set With Custom Comparator. std::set is a C++ STL container that store unique elements following a specific order. It is defined in the set header file. Benefits and Features of std::set[3]:
Explanation: The above comparator function operator () class take two pair of objects at a time and return true if data members of the two operators are the same. There can be any condition as per the need of the problem in the comparator function. In the above example, the function returns true if data members are the same.
Comparator interface is used to order the objects of user-defined classes. A comparator object is capable of comparing two objects of two different classes. Following function compare obj1 with obj2. Syntax: public int compare(Object obj1, Object obj2):
Fraction
is attempted to be copy-constructed from an rvalue.
But constuctor Fraction(Fraction&);
takes a non-constant reference. Non-const references are not allowed to bind to temporaries.
The proper constructor signature should be:
Fraction(const Fraction&);
When you declare a move constructor compiler will move-construct Fraction
from an rvalue instead.
This code compiles with VC++.
It looks like the compiler is not conforming to the standard here.
I could find this StackOverflow question with some more detail. It seems to be a compiler extension that allows this to compile.
If compiler extensions are disabled via /Za
flag it will not compile anymore.
Starting from C++14 the constructor you are trying to use does not participate in overload resolution unless the target function is callable with the given set of arguments (with std::declval<>()
arguments of given types). In your case that would be std::declval<Fraction>()
arguments.
Your FractionComparator
functor is not callable with std::declval<Fraction>()
arguments since it receives its arguments by value, while temporary objects of type Fraction
cannot be copied: Fraction
's copy-constructor's argument is declared as a non-const reference.
Declare your copy constructor as
Fraction(const Fraction &);
and the code will compile. If you have a good reason to keep it as non-const, then you will have to explore other opportunities for making this work. Why does your FractionComparator
insist on receiving its parameters by value anyway?
Your question is tagged C++11, but apparently your compiler is retroactively implementing this C++14 requirement even in C++11 mode.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With