Member function used as lvalue - c++

I'm implementing a Complex class as exercise, and I'm looking at this file as guideline.
At some point in this file I found a strange overloaded operator:
template<typename _Tp>
inline complex<_Tp>
operator+(const complex<_Tp>& __x, const _Tp& __y)
{
complex<_Tp> __r = __x;
__r.real() += __y;
return __r;
}
How It's possible to use __r.real() as lvalue? I tried to implement it in my class, along with the two overloaded definitions of real(), but of course it gives me back a number of errors.
Could someone tell me what I'm missing?
Those are the definitions of the functions real() and imag():
template<typename _Tp>
inline _Tp&
complex<_Tp>::real() { return _M_real; }
template<typename _Tp>
inline const _Tp&
complex<_Tp>::real() const { return _M_real; }
template<typename _Tp>
inline _Tp&
complex<_Tp>::imag() { return _M_imag; }
template<typename _Tp>
inline const _Tp&
complex<_Tp>::imag() const { return _M_imag; }

Its real() is returning a reference to the _M_real; member. The reference can be used as an lvalue.
To make yours able to do the same, you'll need to return a reference as well.

The definition you show for non-const real return an a reference _Tp& which can be used as an l-value just fine. I am guessing your version does not return a reference and therefore will not work.
This article Understanding lvalues and rvalues in C and C++ is a great reference on this topic.

Notice that the implementations return a _Tp&; that is, a reference to _Tp. This makes the return value an l-value.

Related

Why does libstdc++ implement both <L,R> and <LR> overloads for binary operators on iterators?

In libstdc++3, in the header bits/stl_iterator.h (GCC 10 source here), every binary operator for __normal_iterator has two overloads defined (here is == for example):
template<typename _IteratorL, typename _IteratorR, typename _Container>
_GLIBCXX20_CONSTEXPR
inline bool
operator==(const __normal_iterator<_IteratorL, _Container>& __lhs,
const __normal_iterator<_IteratorR, _Container>& __rhs)
_GLIBCXX_NOEXCEPT
{ return __lhs.base() == __rhs.base(); }
template<typename _Iterator, typename _Container>
_GLIBCXX20_CONSTEXPR
inline bool
operator==(const __normal_iterator<_Iterator, _Container>& __lhs,
const __normal_iterator<_Iterator, _Container>& __rhs)
_GLIBCXX_NOEXCEPT
{ return __lhs.base() == __rhs.base(); }
Where .base() returns a pointer to an array element in this case. This is done throughout the library for other iterator types as well. According to comments and changelogs scattered throughout, it's done to support interoperability between iterators and const_iterators.
My question is, why are both the the <_IteratorL, _IteratorR, _Container> and <_Iterator, _Container> overloads defined for all of them? That is, why is <_Iterator, _Container> necessary? Wouldn't the former cover every case? What would break if the latter was removed?
GCC's libstdc++ implementation has a lot of street cred, so I'm sure there's a good, possibly subtle reason, but I can't figure out what it could be.
I ask because I'm currently working out some kinks in my own custom iterator implementations and looking at the STL as a model.
The comment above that complains about std::rel_ops, which provide a template<class T> bool operator!=(const T& lhs, const T& rhs).
Reducing __normal_iterator to it's bare essentials to show the problem, we get this:
#include <utility>
template<typename T>
struct normal_iterator {
T m_base;
const T& base() const { return m_base; }
};
// (1)
template<typename IteratorL, typename IteratorR>
bool operator!=(const normal_iterator<IteratorL>& lhs, const normal_iterator<IteratorR>& rhs) {
return lhs.base() != rhs.base();
}
// (2)
template<typename Iterator>
bool operator!=(const normal_iterator<Iterator>& lhs, const normal_iterator<Iterator>& rhs) {
return lhs.base() != rhs.base();
}
int main() {
using namespace std::rel_ops;
// Your container's `const_iterator` is `const int*`, and `iterator` is `int*`
normal_iterator<const int*> a{nullptr};
normal_iterator<int*> b{nullptr};
a != b; // Uses (1) to compare const_iterator and iterator
a != a; // Uses (2) to compare two iterators
}
Without the second overload, this would not compile since there are two viable functions to call:
std::rel_ops::operator!=<normal_iterator<int*>>(const normal_iterator<int*>&, const normal_iterator<int*>&)
operator!=<int*, int*>(const normal_iterator<int*>&, const normal_iterator<int*>&)
And neither is more specialiased than the other (it is ambiguous)
For std::rel_ops specifically, there is no reason for the extra == overload, but nothing is stopping a user from writing a similar template<typename T> bool operator==(const T&, const T&) in some other namespace.

How is BOOST_PREVENT_MACRO_SUBSTITUTION supposed to work?

I'm reading boost's config/suffix.hpp, and I'm surprised with the following code:
// Workaround for the unfortunate min/max macros defined by some platform headers
#define BOOST_PREVENT_MACRO_SUBSTITUTION
// <skipped unimportant lines>
namespace std {
template <class _Tp>
inline const _Tp& min BOOST_PREVENT_MACRO_SUBSTITUTION (const _Tp& __a, const _Tp& __b) {
return __b < __a ? __b : __a;
}
template <class _Tp>
inline const _Tp& max BOOST_PREVENT_MACRO_SUBSTITUTION (const _Tp& __a, const _Tp& __b) {
return __a < __b ? __b : __a;
}
}
This actually seems to be a valid thing to make the definitions of min and max functions compile when the same-named macros are defined. But why would this be useful at the actual call site? Wouldn't the macro actually substitute when the functions are called? I've tried to make a simple test, "emulating" this setup:
#include <iostream>
#define PREVENT_MACRO_SUBSTITUTION
#define max(x,y) ((x)<(y)?(y):(x))
namespace test
{
int max PREVENT_MACRO_SUBSTITUTION (int a, int b)
{
std::cerr << "Function max\n";
return a<b?b:a;
}
}
int main()
{
int x=test::max(5,6);
std::cout << "x="<<x<<"\n";
}
And, as expected, I get a compilation error due to expansion of max macro. So, how is boost's macro substitution prevention supposed to work?
It's not supposed to do what you think it's supposed to do.
If a min or max macro is defined, and the user wishes to call those std::min or std::max functions, it's the user's responsibility to make sure the macro is suppressed. Possibly again using BOOST_PREVENT_MACRO_SUBSTITUTION, possibly using parentheses ((std::min) (...)).
All the use of BOOST_PREVENT_MACRO_SUBSTITUTION is doing here is preventing a syntax error from being raised for the definition of std::min and std::max, like you figured out already. It would happily expand min as a macro if the header had used inline const _Tp& min (const _Tp& __a, const _Tp& __b), resulting in something like inline const _Tp& ((const _Tp& __a) < (const _Tp& __b) ? (const _Tp& __a) : (const _Tp& __b)). But if code doesn't actually use min or max, then including that header file should be harmless.

when using templates C++ "const" mystery overloaded function call

I have a question with the code below. When I compile it it complains with this error below. Now my question is if I remove the "const" in the declaration and change it to only :
template<class T> T max( T& left, T& right);
it becomes okay and the compiles/executes correctly. How come the compiler thinks that the call is ambiguous? Shouldn't the forward declaration follow the implementation?
==== start of error message====
max.cpp:10:34: error: call of overloaded ‘max(int, int)’ is ambiguous
max.cpp:10:34: note: candidates are:
max.cpp:5:21: note: T max(const T&, const T&) [with T = int]
/usr/include/c++/4.6/bits/stl_algobase.h:210:5: note: const _Tp& std::max(const _Tp&, const _Tp&) [with _Tp = int]
max.cpp:11:44: error: call of overloaded ‘max(double, double)’ is ambiguous
max.cpp:11:44: note: candidates are:
max.cpp:5:21: note: T max(const T&, const T&) [with T = double]
=======end of error message===
=============code starts here======
#include<iostream>
using namespace std;
template<class T> T max(const T& left, const T& right);
int main(void)
{
cout<<"max int:"<< max(1,4)<<endl;
cout<<"max double:"<< max(5.02,1.002)<<endl;
}
template<class T>
T max(const T& left, const T& right)
{
return left > right? left:right;
}
You have to do:
cout<<"max int:"<< ::max(1,4)<<endl;
cout<<"max double:"<< ::max(5.02,1.002)<<endl;
Since there is another max defined in std namespace. You have to inform the compiler to use the max defined in global namespace, which is the one you defined. See a live example here: Function template Demo
If you look at the std::max defined in std namespace:
template <class T> const T& max (const T& a, const T& b);
which returns const reference and takes const reference to parameters, that's why when you remove const, it will compile. Hope that this helps.
The std namespace has a max already built in, so you can either not have the line using namespace std; or put the max function in your own namespace.
namespace myNamespace {
//your max function
}
We have few functions already defined in std namespace like max(), swap() qsort(). So when you define your own function
max(const T& left,const T& right)
it is same as one in std namespace hence the error. So you can do following to make it work
call your function using scope resolution operator ::max(x,y)
remove const qualifier from your function
As others have written the compiler has found a max function additionally in namespace std. Now it tries to get the best version for you via function overloading. As both signatures are eaqual it can not choose a best version and complains. Now if you remove const the compiler can not bind a integer (or double) literal to a non const refference. Now it has only one choice and takes std::max functionality. You can see it with the following example:
#include <iostream>
namespace ns1 {
template<class T>
void doit(T const&) {
std::cout << "ns1::doit" << std::endl;
}
}
template<class T>
void doit(T&) {
std::cout << "::doit" << std::endl;
}
int main() {
using namespace ns1;
int i=1;
int const j=1;
doit(1);
doit(i);
doit(i+1-1);
doit(j);
return 0;
}
As everithing is an int the compiler has to choose a non const reference only if it has a non const variable (i). In other cases it choose the cont reference version from namespace ns1. It could even bind temporaries to const references (i+1-1).The same happens with your max and std::max.
Edit:
I forgott to say if you remove the const in your declaration the compiler choose std::max which is of course correct but not yours.

C++ template class compilation error

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.

C++ boost function overloaded template

I cannot figure out why this segment gives unresolved overloaded function error (gcc version 4.3.4 (Debian 4.3.4-6)):
#include <algorithm>
#include <boost/function.hpp>
// this does not work
int main1()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
// this does not work
int main2() {
typedef boost::function2<const int&, const int&, const int&> max;
max m(static_cast<max>(&std::max<int>));
}
can you help me, thanks
test.cpp: In function âint main()â:
test.cpp:7: error: no matching function for call to âboost::function2<const int&, const int&, const int&>::function2(<unresolved overloaded function type>)â
/usr/include/boost/function/function_template.hpp:747: note: candidates are: boost::function2<R, T1, T2>::function2(const boost::function2<R, T1, T2>&) [with R = const int&, T0 = const int&\
, T1 = const int&]
/usr/include/boost/function/function_template.hpp:739: note: boost::function2<R, T1, T2>::function2(boost::function2<R, T1, T2>::clear_type*) [with R = const int&, T0 = cons\
t int&, T1 = const int&]
/usr/include/boost/function/function_template.hpp:707: note: boost::function2<R, T1, T2>::function2() [with R = const int&, T0 = const int&, T1 = const int&]
max/min is defined as
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
__glibcxx_function_requires(_LessThanComparableConcept<_Tp>)
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
I have tried all sorts of template explicit instantiation but nothing seems to work. Same problem appears with g++ 4.1 but not with ICC
this works
#include <algorithm>
#include <boost/function.hpp>
namespace std_ {
template<typename _Tp>
inline const _Tp&
max(const _Tp& __a, const _Tp& __b)
{
// concept requirements
//return __a < __b ? __b : __a;
if (__a < __b)
return __b;
return __a;
}
}
int main()
{
typedef const int &T;
typedef boost::function<T(T,T)> min_;
//typedef const int&(*min_)(const int&, const int&);
min_ m(::std_::max<int>);
}
and this
#include <algorithm>
#include <boost/function.hpp>
int main()
{
//typedef const int &T;
//typedef boost::function<T(T,T)> min_;
typedef const int&(*min_)(const int&, const int&);
min_ m(::std::max<int>);
}
Update: this is a gcc bug that has been fixed in gcc >=4.4. bugzilla. Also, revised my answer with a reduced test case.
There are two components to this problem: the way boost::function adopts a function pointer and the gcc bug.
boost::function - There is something strange about the error message you listed in the question; there is no candidate constructor that accepts anything like a function address. Digging into the boost::function src, the relevant constructor is (leaving out the enable_if argument):
template<typename Functor>
function(Functor f) : base_type(f) {}
So boost::function doesn't help you out at all in specifying the type of a function pointer; if the function is overloaded the address must be cast to specify its type. If an overloaded function address is used, the above template can't be instantiated, and therefore the appropriate constructor doesn't show up in the error message.
gcc bug - If you look at the stl_algobase.h header again, you'll see there are two templates named max, a two param version and a one param version. This shouldn't be a problem with you code though, right? The term &max<int> should instantiate the single param version and take its address. However, that is not what happens. You can see the problem in the reduced (no header) test case:
template <class T>
const T& max(const T& x, const T& y){
return x > y ? x : y;
}
template <class T, class C>
const T& max(const T& x, const T& y, C comp){
return comp(x, y) ? y : x;
}
template <class R, class A0, class A1>
struct functor{
template <class F>
functor(F f) : f(f) {}
R (*f)(A0, A1);
};
int main(void){
functor<const int&, const int&, const int&> func(&max<int>);
return 0;
}
The above code results in a unresolved overloaded function type with gcc 4.3.4. The fix is either to remove the template <class T, class C> max(...){...} definition or add a static_cast<const int& (*)(const int&, const int&)>(...) around the function address. I'm guessing the problem has to do with incorrect application of partial explicit parameter specification, which is specified by the standard. It lets you leave out trailing template parameters to do things like specify a return value type and not the argument types. That is, the compiler instantiates both template when it should only instantiate the fully specified template. Its moot speculation though, since the bug has been fixed in gcc >= 4.4.
Since one shouldn't hack at stl_algobase.h ;) , the work around Vicente suggests is the correct one, namely cast the function pointer to the desired function pointer type const int& (*)(const int&, const int&). In your code, the cast doesn't work because, as GMan points out, you are casting to a boost::function<...>, which does nothing to resolve the function pointer ambiguity.
To critique the code, there's no reason to static_cast that. Consider all the cast is going to do is use the constructor of boost::function2 to make a new boost::function2, then it will be copy-constructed into m. Just construct directly into m:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function2<const int&, const int&, const int&> max;
max m(&std::max<int>);
}
Lastly, the preferred syntax of boost::function is:
#include <algorithm>
#include <boost/function.hpp>
int main()
{
typedef boost::function<const int&(const int&, const int&)> max;
max m(&std::max<int>);
}
The n-ary specific classes are for older compiler support.
It seems to be a problem with the definition of the std::max template function with releases of gcc < 4.4
With gcc-4.4.0 and msvc Express9 it works.
The following works also for gcc-3.4 and gcc-4.3
int main1()
{
int res = std::max(1,2);
typedef boost::function<const int&(const int&, const int&)> max;
max m(static_cast<const int&(*)(const int&, const int&)>(std::max<int>));
return 0
}