C++ template class compilation error - c++

I get the following compilation error:
main.cc: In function 'int main(int, char**)':¶
main.cc:200: error: no match for 'operator==' in 'rt1 == rt2'¶
triple.hh:124: note: candidates are: bool Triple<T1, T2, T3>::operator==(const Triple<T1,T2, T3>&) [with T1 = int, T2 = int, T3 = int] <near match>¶
main.cc:27: note: bool operator==(const Special&, const Special&)¶
Although I have implemented the operator== overload as follows for my template class:
bool operator==(const Triple<T1, T2, T3>& another) {
return (a == another.first() and b == another.second() and c == another.third());
}
For my template class:
template <typename T1, typename T2, typename T3>
class Triple
Do you know what the problem might be? Many thanks.

Your boolean operator is declared as non-const. Fix it as follows in case rt1 is a const reference. Note the added const keyword.
bool operator==(const Triple<T1, T2, T3>& another) const {
Explanation: C++ has two basic syntaxes for overloading a comparison operator; a member operator with one other argument, or a static operator with two arguments. However, in both cases, you should make sure that both operands are const, with the respective syntaxes.
It is theoretically possible to supply different const and non-const versions of the operator that do subtly different things, so the compiler calls yours a near-match, but nevertheless not a match.

Related

Invalid operands to binary expression error (missing const) in std::sort: Why does specifying the compare operator solve it?

Considering:
#include <algorithm>
#include <vector>
struct A {
double dummy;
bool operator<(const A& a) { ///Here I am missing a `const`
return dummy < a.dummy;
}
};
int main()
{
std::vector<A> a;
a.push_back({0.9});
a.push_back({0.4});
std::sort(a.begin(),a.end());
return 0;
}
This compiles fine on gcc, but on clang it gives
/usr/include/c++/v1/algorithm:719:71: error: invalid operands to binary expression ('const A' and 'const A')
bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;}
and a long list of failed instantiation.
Here is my minimal example in action: https://rextester.com/VEO17629
I could finally solve it when I found Invalid operand to binary expression on std::max_element (the operator < must have a const specifier).
The curious thing is that the error goes away also if I call std::sort specifying the operator std::less<>():
std::sort(a.begin(),a.end(),std::less<>());
Why does specifying the compare operator std::less<>() solve the error?
Why does specifying the compare operator std::less<>() solve the error?
Interestingly enough, it's only when you use std::less<void> (std::less<>) that it compiles. std::less<A> does not.
std::less<A>::operator():
constexpr bool operator()( const T& lhs, const T& rhs ) const;
The std::less<void>::operator() has a slightly different signature, not specifying const T&:
template< class T, class U>
constexpr auto operator()( T&& lhs, U&& rhs ) const
-> decltype(std::forward<T>(lhs) < std::forward<U>(rhs));
So, the std::less<void>::operator() is free to call the non-const operator<.
The difference between g++ (libstdc++) and clang++ (libc++) can have some different explanations. One would be if libstdc++ forwards std::sort(a.begin(),a.end()) to std::sort(a.begin(),a.end(), std::less<>{}) instead of using operator< directly.
In C++14 (that you used in your demo) [alg.sorting]/1 just says: "All the operations in 25.4 have two versions: one that takes a function object of type Compare and one that uses an operator<.".
There is nothing prohibiting using std::less<void> to call operator<.
In C++20
[sort]/1 there has even been an addition, specifying exactly that behavior when no comparator is given:
"Let comp be less{} and proj be identity{} for the overloads with no parameters by those names.". clang++/libc++ in C++20 mode fails to comply to this though.

Why less than operator accepts different types of params while std::min not?

#include <iostream>
int main(){
int a = 1;
long long b = 2;
std::cout<<(a<b);
std::cout<<std::min(a, b);
return 0;
}
> In file included from /usr/include/c++/4.8/bits/char_traits.h:39:0,
> from /usr/include/c++/4.8/ios:40,
> from /usr/include/c++/4.8/ostream:38,
> from /usr/include/c++/4.8/iostream:39,
> from sum_to.cpp:1: /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template<class
> _Tp, class _Compare> const _Tp& std::min(const _Tp&, const _Tp&, _Compare)
> min(const _Tp& __a, const _Tp& __b, _Compare __comp)
> ^ /usr/include/c++/4.8/bits/stl_algobase.h:239:5: note: template argument deduction/substitution failed: sum_to.cpp:7:29:
> note: deduced conflicting types for parameter ‘const _Tp’ (‘int’ and
> ‘long long int’)
> std::cout<<std::min(a, b);
---
Thanks to chris comment in function overloading post
Template argument deduction doesn't take conversions into account. One
template parameter can't match two types
So std::min fail.
Why < would work?
Because built-in < applies Numeric promotions, and template argument deduction doesn't.
As explained in other answers, the reason is that std::min requires the types of the arguments to be identical if deduction is to be performed, while < implies the usual arithmetic conversions (§5.9/2), which will make sure that the types are converted to a "common denominator". Note how §13.6/12 lists up built-in operators as candidates:
For every pair of promoted arithmetic types L and R, there exist
candidate operator functions of the form
// […]
LR operator<(L , R );
// […]
where LR is the result of the usual arithmetic conversions between
types L and R.
Actually, std::min should be able to deal with distinct types. The following is a more modern approach:
template <typename T>
constexpr decltype(auto) min(T&& t) {return std::forward<T>(t);}
template <typename T, typename U, typename... Args>
constexpr auto min(T&& t, U&&u, Args&&... args) {
std::common_type_t<T, U> const& _t(std::forward<T>(t)), _u(std::forward<U>(u));
return min(_t<_u? _t : _u, std::forward<Args>(args)...);
}
Demo.
It is because std::min is a template function.
template <class T> const T& min (const T& a, const T& b) {
return !(b<a)?a:b; // or: return !comp(b,a)?a:b; for version (2)
}
so it needs the arguments to have the same type, but if you use (a<b), so a could implicitly converted to a long long
The < operator is binary, so the compiler could convert arguments to the same type and compare them.
Otherwise min function should return something. How could compiler guess which type should he return?
Primitive types don't overload operators, so usual arithmetic conversions are applied and your int is converted to a long long, and the "<" has a valid meaning.
You can't even overload operators for primitive types:
https://isocpp.org/wiki/faq/intrinsic-types#intrinsics-and-operator-overloading
Example to show that your int is promoted to long long
// common_type example
#include <iostream>
#include <type_traits>
int main() {
typedef std::common_type<int, long long>::type A; // i
std::cout << "A: " << std::is_same<long long,A>::value << std::endl;
return 0;
}
Documentation
http://en.cppreference.com/w/cpp/language/operator_arithmetic
For the binary operators (except shifts), if the promoted operands
have different types, additional set of implicit conversions is
applied, known as usual arithmetic conversions with the goal to
produce the common type (also accessible via the std::common_type type
trait)

std::make_pair type deduction

I came across some odd thing I would like to have an explanation for. The following code snippet provides a simple class template type and two operator<<s: one for specializations of type and one for a std::pair of type specializations.
#include <ostream>
#include <utility>
template <typename T>
class type {
public:
T value_;
};
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, type<T> const& a)
{
return os << a.value_;
}
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
{
return os << a.first << ',' << a.second;
}
#include <iostream>
int
main()
{
using float_type = type<float>;
float_type const a = { 3.14159 };
float_type const b = { 2.71828 };
#if 0
std::cout << std::make_pair(a, b)
<< std::endl;
#else
std::cout << std::pair<float_type const, float_type const>(a, b)
<< std::endl;
#endif
}
The main function provides a specialization and two variables of that specialization. There are two variants for displaying the variables as a std::pair. The first fails because std::make_pair seems to strip the const specifier from the variables, which in turn doesn't match with the signature of the second operator<<: std::pair<T const, T const>. However, constructing a std::pair specialization (second std::cout line in main) works as well as removing the const specification for T from operator<< for std::pair, i.e. std::pair<T, T>.
Compiler messages::
gcc 4.9.2
std_make_pair.cpp: In function 'int main()':
std_make_pair.cpp:52:35: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
std::cout << std::make_pair(a, b) << std::endl;
^
In file included from std_make_pair.cpp:3:0:
/usr/include/c++/4.9.2/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::pair<type<float>, type<float> >]'
operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
^
clang 3.5 (non-viable functions from system headers removed)
std_make_pair.cpp:52:13: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>')
and 'pair<typename __decay_and_strip<const type<float> &>::__type, typename __decay_and_strip<const
type<float> &>::__type>')
std::cout << std::make_pair(a, b) << std::endl;
~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~
std_make_pair.cpp:30:1: note: candidate template ignored: can't deduce a type for 'T' which would make
'const T' equal 'type<float>'
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T const, T const> const& a)
so, here's the question: am I supposed to specify an operator<< taking a std::pair of T instead of T const? Isn't that watering down the contract I'm setting up with any user of the functionality, i.e. with T const I basically promise to use T only in non-mutating ways?
The first fails because std::make_pair seems to strip the const specifier from the variables, which in turn doesn't match with the signature of the second operator<<: std::pair<T const, T const>
That is correct. make_pair is a function template that relies on std::decay to explicitly drop const, volatile, and & qualifiers:
template <class T1, class T2>
constexpr pair<V1, V2> make_pair(T1&& x, T2&& y);
Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y));
where V1 and V2 are determined as follows: Let Ui be decay_t<Ti> for each Ti. Then each Vi is X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui.
The compiler is completely correct to reject your code - you added a stream operator for pair<const T, const T>, but are trying to stream a pair<T, T>. The solution is to just remove the extra const requirement in your stream operator. Nothing in that function requires that the pair consist of const types - just that the types themselves are streamable, which is independent of their constness. There is nothing wrong with this:
template <typename CTy, typename CTr, typename T>
std::basic_ostream<CTy,CTr>&
operator<<(std::basic_ostream<CTy,CTr>& os, std::pair<T, T> const& a)
{
return os << a.first << ',' << a.second;
}
You're already taking the pair by reference-to-const, it's not like you can modify its contents anyway.

How does make_pair know the types of its args?

The definition for make_pair in the MSVC++ "utility" header is:
template<class _Ty1,
class _Ty2> inline
pair<_Ty1, _Ty2> make_pair(_Ty1 _Val1, _Ty2 _Val2)
{ // return pair composed from arguments
return (pair<_Ty1, _Ty2>(_Val1, _Val2));
}
I use make_pair all the time though without putting the argument types in angle brackets:
map<string,int> theMap ;
theMap.insert( make_pair( "string", 5 ) ) ;
Shouldn't I have to tell make_pair that the first argument is std::string and not char* ?
How does it know?
Function template calls can usually avoid explicit template arguments (ie make_pair<…>) by argument deduction, which is defined by C++03 §14.8.2. Excerpt:
When a function template
specialization is referenced, all of
the template arguments must have
values. The values can be either
explicitly specified or, in some
cases, deduced from the use.
The specific rules are a bit complicated, but typically it "just works" as long as you have only one specialization which is generally qualified enough.
Your example uses two steps of deduction and one implicit conversion.
make_pair returns a pair<char const*, int>,
then template<class U, classV> pair<string,int>::pair( pair<U,V> const & ) kicks in with U = char*, V = int and performs member-wise initialization,
invoking string::string(char*).
It doesn't. make_pair generated a pair<char*,int> (or maybe a pair<char const*,int>).
However, if you'll note in the implementation of pair there's a templated copy constructor:
template < typename Other1, typename Other2 >
pair(pair<Other1,Other2>& other)
: first(other.first), second(other.second)
{}
This may be implemented in slightly different ways but amounts to the same thing. Since this constructor is implicit, the compiler attempts to create pair<std::string,int> out of your pair<char*,int> - since the necessary types are convertible this works.
make_pair() exists precisely so that argument type deduction can be used to determine the template parameter types.
See this SO question: Using free function as pseudo-constructors to exploit template parameter deduction
It relies on the fact that the constructor of std::string accepts a const char*.
It doesn't matter if this constructor of std::string is explicit or not. The template deducts the type and uses the copy constructor of pair to convert it. It also doesn't matter whether or not the pair constructor is explicit.
If you turn the constructor of std::string into:
class string
{
public:
string(char* s)
{
}
};
you get this error:
/usr/include/c++/4.3/bits/stl_pair.h: In constructor ‘std::pair<_T1, _T2>::pair(const std::pair<_U1, _U2>&) [with _U1 = const char*, _U2 = int, _T1 = const string, _T2 = int]’:
foo.cpp:27: instantiated from here
/usr/include/c++/4.3/bits/stl_pair.h:106: error: invalid conversion from ‘const char* const’ to ‘char*’
/usr/include/c++/4.3/bits/stl_pair.h:106: error: initializing argument 1 of ‘string::string(char*)’
The constructor looks like this:
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }
The copy constructor looks like this:
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }

Odd behavior when recursively building a return type for variadic functions

This is probably going to be a really simple explanation, but I'm going to give as much backstory as possible in case I'm wrong. Advanced apologies for being so verbose. I'm using gcc4.5, and I realize the c++0x support is still somewhat experimental, but I'm going to act on the assumption that there's a non-bug related reason for the behavior I'm seeing.
I'm experimenting with variadic function templates. The end goal was to build a cons-list out of std::pair. It wasn't meant to be a custom type, just a string of pair objects. The function that constructs the list would have to be in some way recursive, with the ultimate return value being dependent on the result of the recursive calls. As an added twist, successive parameters are added together before being inserted into the list. So if I pass [1, 2, 3, 4, 5, 6] the end result should be {1+2, {3+4, 5+6}}.
My initial attempt was fairly naive. A function, Build, with two overloads. One took two identical parameters and simply returned their sum. The other took two parameters and a parameter pack. The return value was a pair consisting of the sum of the two set parameters, and the recursive call. In retrospect, this was obviously a flawed strategy, because the function isn't declared when I try to figure out its return type, so it has no choice but to resolve to the non-recursive version.
That I understand. Where I got confused was the second iteration. I decided to make those functions static members of a template class. The function calls themselves are not parameterized, but instead the entire class is. My assumption was that when the recursive function attempts to generate its return type, it would instantiate a whole new version of the structure with its own static function, and everything would work itself out.
The result was: "error: no matching function for call to BuildStruct<double, double, char, char>::Go(const char&, const char&)"
The offending code:
static auto Go(const Type& t0, const Type& t1, const Types&... rest)
-> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
My confusion comes from the fact that the parameters to BuildStruct should always be the same types as the arguments sent to BuildStruct::Go, but in the error code Go is missing the initial two double parameters. What am I missing here? If my initial assumption about how the static functions would be chosen was incorrect, why is it trying to call the wrong function rather than just not finding a function at all? It seems to just be mixing types willy-nilly, and I just can't come up with an explanation as to why. If I add additional parameters to the initial call, it always burrows down to that last step before failing, so presumably the recursion itself is at least partially working. This is in direct contrast to the initial attempt, which always failed to find a function call right away.
Ultimately, I've gotten past the problem, with a fairly elegant solution that hardly resembles either of the first two attempts. So I know how to do what I want to do. I'm looking for an explanation for the failure I saw.
Full code to follow since I'm sure my verbal description was insufficient. First some boilerplate, if you feel compelled to execute the code and see it for yourself. Then the initial attempt, which failed reasonably, then the second attempt, which did not.
#include <iostream>
using std::cout;
using std::endl;
#include <utility>
template<typename T1, typename T2>
std::ostream& operator <<(std::ostream& str, const std::pair<T1, T2>& p) {
return str << "[" << p.first << ", " << p.second << "]";
}
//Insert code here
int main() {
Execute(5, 6, 4.3, 2.2, 'c', 'd');
Execute(5, 6, 4.3, 2.2);
Execute(5, 6);
return 0;
}
Non-struct solution:
template<typename Type>
Type BuildFunction(const Type& t0, const Type& t1) {
return t0 + t1;
}
template<typename Type, typename... Rest>
auto BuildFunction(const Type& t0, const Type& t1, const Rest&... rest)
-> std::pair<Type, decltype(BuildFunction(rest...))> {
return std::pair<Type, decltype(BuildFunction(rest...))>
(t0 + t1, BuildFunction(rest...));
}
template<typename... Types>
void Execute(const Types&... t) {
cout << BuildFunction(t...) << endl;
}
Resulting errors:
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:33:35: instantiated from here
test.cpp:28:3: error: no matching function for call to 'BuildFunction(const int&, const int&, const double&, const double&, const char&, const char&)'
Struct solution:
template<typename... Types>
struct BuildStruct;
template<typename Type>
struct BuildStruct<Type, Type> {
static Type Go(const Type& t0, const Type& t1) { return t0 + t1; }
};
template<typename Type, typename... Types>
struct BuildStruct<Type, Type, Types...> {
static auto Go(const Type& t0, const Type& t1, const Types&... rest)
-> std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))> {
return std::pair<Type, decltype(BuildStruct<Types...>::Go(rest...))>
(t0 + t1, BuildStruct<Types...>::Go(rest...));
}
};
template<typename... Types>
void Execute(const Types&... t) {
cout << BuildStruct<Types...>::Go(t...) << endl;
}
Resulting errors:
test.cpp: In instantiation of 'BuildStruct<int, int, double, double, char, char>':
test.cpp:33:3: instantiated from 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]'
test.cpp:38:41: instantiated from here
test.cpp:24:15: error: no matching function for call to 'BuildStruct<double, double, char, char>::Go(const char&, const char&)'
test.cpp:24:15: note: candidate is: static std::pair<Type, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...))> BuildStruct<Type, Type, Types ...>::Go(const Type&, const Type&, const Types& ...) [with Type = double, Types = {char, char}, decltype (BuildStruct<Types ...>::Go(BuildStruct<Type, Type, Types ...>::Go::rest ...)) = char]
test.cpp: In function 'void Execute(const Types& ...) [with Types = {int, int, double, double, char, char}]':
test.cpp:38:41: instantiated from here
test.cpp:33:3: error: 'Go' is not a member of 'BuildStruct<int, int, double, double, char, char>'
Reading the comments, it seems clear enough that this is a very localized bug in a particular version of G++, and that's all the answer there will ever be.