How is BOOST_PREVENT_MACRO_SUBSTITUTION supposed to work? - c++

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.

Related

Why max() function in C++ giving error "no matching function for call to max"? Same code works if I do it explicitly with conditional statement

Both parameters of max are of type int, then why am I getting this error?
Code is to find maximum depth of paranthesis in a string
int maxDepth(string s) {
stack<char> stac;
int maxDepth = 0;
for(auto &elem: s) {
if(elem == '(')
stac.push(elem);
else if(elem == ')')
{
// maxDepth = max(maxDepth, stac.size()); // this doesn't work
if(stac.size() > maxDepth) // this works, why?
maxDepth = stac.size();
stac.pop();
}
}
return maxDepth;
}
The reason why your compiler reject your call to std::max function is because it cannot deduce the type it need.
Below is typical implementation of std::max
template<typename _Tp>
_GLIBCXX14_CONSTEXPR
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;
}
so both parameters receive _Tp but the way how template type deduction work is it evaluate the type for each of the template parameters and then compare if they match. and since one of your parameter are int and other is size_t which is unsigned int then you will have an error.
When using the std::max what you can do.
do cast so the parameters match: maxDepth = max(static_cast<size_t>(maxDepth), stac.size());
declare the type - which is also more readable: maxDepth = max<size_t>(maxDepth, stac.size())
Regarding your own program, i advice that change the type of maxDepth to size_t.
and also for readability change the function name so it will not hold the same name as the variable.
Hope it clear things out.

overloading error for C++ template function

I am trying to do some practice with function templates as in the following example:
#include <iostream>
using namespace std;
template <class T>
T max(T a, T b)
{
return a > b ? a : b;
}
int main()
{
cout << "max(10, 15) = " << max(10, 15) << endl;
retun 0;
}
But I got the following errors. Could anybody recognize where the problem is?
..\src\main.cpp:59:40: error: call of overloaded 'max(int, int)' is
ambiguous
cout << "max(10, 15) = " << max(10, 15) << endl;
^
..\src\main.cpp:16:3: note: candidate: 'T max(T, T) [with T = int]'
T max(T a, T b)
^~~
In file included from c:\mingw\include\c++\8.1.0\bits\char_traits.h:39,
from c:\mingw\include\c++\8.1.0\ios:40,
from c:\mingw\include\c++\8.1.0\ostream:38,
from c:\mingw\include\c++\8.1.0\iostream:39,
from ..\src\main.cpp:9:
c:\mingw\include\c++\8.1.0\bits\stl_algobase.h:219:5: note:
candidate: 'constexpr const _Tp& std::max(const _Tp&, const _Tp&)
[with _Tp = int]'
max(const _Tp& __a, const _Tp& __b)
I am sorry I am new to templates. Thanks for your help.
Your usage of templates is correct, but the compiler complains that there already is a function called max with same arguments.
It's full name would be std::max, but because you wrote using namespace std its just max and compiler cannot know which function to call.
Solution is not to use using, see Why is "using namespace std" considered bad practice? .
using namespace std; is the issue
Please stop using that, see why
The iostream header includes another header file that pulls std::max, giving a compiler error.

anyone has a solution for this gcc compiler error: macro "min" passed 3 arguments but takes just two

This is my code:
template<typename _Tp, typename _Compare>
inline const _Tp&
inline min(const _Tp& __a, const _Tp& __b, _Compare& __comp)
{
if (__comp(__b, __a))
return __b ;
return __a;
}
this is the error message I am getting:
/usr/include/c++/4.4/bits/stl_algobase.h:232:57: error: macro "min" passed 3 arguments, but takes just 2
I understand I am passing 3 arguments a,b and comp but I am only returning a and b, however when I try to return comp it gives me the same message.
You have #define min(a, b) somewhere, so pre-processor try to expand it and failed
Try (min)(a, b, compare). The parentheses around min prevent macro expansion.

Member function used as lvalue

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.

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.