log contaminates global namespace
1Hyena opened this issue · 12 comments
CImg only defines a method CImg<T>::log()
. It should not induce any conflict with other log()
functions.
A conflict may occur if you have conflicting macros defined in your global namespace, but not functions.
You're right. It wasn't that, it's something else though. Here's the minimal version of my code that causes this error.
#include <iostream>
#include <functional>
#include <CImg.h>
void log(const char *text) {
std::cerr << text << "\n";
}
bool deserialize(
int argc, char **argv,
const std::function<void(const char *text)>& log_callback
) {
return true;
}
int main(int argc, char **argv) {
if (!deserialize(argc, argv, log)) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
And here's the compiler error:
main.cpp: In function ‘int main(int, char**)’:
main.cpp:17:21: error: invalid initialization of reference of type ‘const std::function<void(const char*)>&’ from expression of type ‘<unresolved overloaded function type>’
17 | if (!deserialize(argc, argv, log)) {
| ~~~~~~~~~~~^~~~~~~~~~~~~~~~~
main.cpp:11:50: note: in passing argument 3 of ‘bool deserialize(int, char**, const std::function<void(const char*)>&)’
11 | const std::function<void(const char *text)>& log_callback
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
make[1]: *** [Makefile:41: obj/main.o] Error 1
make: *** [Makefile:18: all] Error 2
Any ideas what could be going wrong?
No idea, sorry. Does this compiles when CImg.h
is not included ?
Yes, then it compiles without any problems.
It has to be something to do with log()
indeed. If I rename log()
to log3()
in your example, it compiles.
I have a work-around:
namespace my_log {
void log(const char *text) {
std::cerr << text << "\n";
}
}
bool deserialize(
int argc, char **argv,
const std::function<void(const char *text)>& log_callback
) {
return true;
}
int main(int argc, char **argv) {
if (!deserialize(argc, argv, my_log::log)) {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
but I still don't get why using just log
doesn't work.
Thanks, I changed the name of the function, for now, but in the long term this should be fixed on the library side. Unfortunately I also don't have a clue why this happens. The following lines from CImg.h are suspicious though:
#define _cimg_create_pointwise_function(name) \
template<typename T> \
inline CImg<_cimg_Tfloat> name(const CImg<T>& instance) { \
return instance.get_##name(); \
}
_cimg_create_pointwise_function(sqr)
_cimg_create_pointwise_function(sqrt)
_cimg_create_pointwise_function(erf)
_cimg_create_pointwise_function(exp)
_cimg_create_pointwise_function(log)
Yes, these line actually creates a log()
function for CImg<T>
objects, so that a user can do this:
CImg<> img("filename.bmp");
CImg<> img_log = log(img);
But removing the line _cimg_create_pointwise_function(log)
does not solve the compilation issue.
OK, so I've found the problem. It doesn't come from CImg, but from cmath
.
Replacing #include "CImg.h"
by #include <cmath>
raises exactly the same problem.
(and of course, CImg actually includes cmath
by default).
Interesting. I thought the c prefix headers such as cmath enabled their respective functions via the std namespace. So one would call std::log instead of just log.
In theory yes, but I think g++
is a bit sloppy about that rule by default, so using log()
rather than std::log()
still works.
It's unfortunate that such things happen as they are tedious to track down but there's not much we can do about it. It is what it is. I recall having similar issues elsewhere too. Would be great if CImg didn't even include such toxic headers but sometimes it's practically impossible.