I'm trying to convert a working define which prints the argument into a proper function, but I'm unsure of the variable type.
The working method I have is:
#define WARN(x) std::cout << "WARNING! " << x << "!" << std::endl;
Which I can then pass a sentence similar to using std::cout
WARN("This is a test warning." << " And this is some more stuff...");
However, I feel this should be more neatly wrapped into a function rather than using a define.
Please could you help me understand how the preprocessor is interpreting the variable x, and how I can translate the define into a function.
P.S. I am aware that I could use a variadic function, but I'd rather not have to pass the number of arguments and would rather avoid variadic altogether anyway.
but I'm unsure of the variable type.
That's where use of function templates can provide a clean solution.
template <typename T>
void WARN(T const& x)
{
std::cout << "WARNING! " << x << "!" << std::endl;
}
is a good replacement for
#define WARN(x) std::cout << "WARNING! " << x << "!" << std::endl;
Related
Recently I came across inline in c++17 and how it been used as an alternative to #define but both have its downsides. However my question is that if I want to cramp the whole std::cout << x << '\n'; in one simple line called LOG(x).
A: What should I use and why?
B: What are the pros and cons of each and when to use what?
1.)
#define LOG(x) std::cout << x << '\n'
2.)
void inline LOG(auto x)
{
std::cout << x << '\n';
}
3.)
void LOG(auto x)
{
std::cout << x << '\n';
}
4.)
This one was suggested to me by someone:
template <typename T>
void log(const T& x)
{
std::cout << x << '\n';
}
How to use Macros in c++?
Sparingly. When there is no better alternative.
Avoid this. Macros names don't respect scoping rules and thus are much more susceptible to name clashes. Also, consider what happens if you wanted to log a number bitshifted by another number:
LOG(0x1 << 2);
What output would you expect, and what output do you get? Do they match?
Pro: It is a function (template) and thus doesn't have the problems associated with macros. Con: You accept the parameter by value. This can be expensive with for example strings which are quite often used for logging. Requires C++20.
Practically identical to 2. The auto parameter turns these into function templates which are implicitly inline.
Pro: Doesn't require C++20. A reference is passed, which is good for passing strings.
In conclusion: 4. is a reasonable default choice.
The general consensus is that using macros is not a good idea. BUT what that really means is that ABUSE of macros is not a good idea.
Solution #2 is OK, but its usefulness is rather limited, since you can only print one value per line.
inline void LOG(const auto& x)
{
std::cout << x << '\n';
}
// use as:
LOG(x);
And it's an OK solution, but its usage is rather limited.. Consider this use case:
inline void LOG(const auto& x)
{
std::cout << x << '\n';
}
struct point { float x, y; };
// usability is kind of limited, since it will only print one value per line
point p{};
LOG(x);
LOG(y);
// which gives this output.
0
0
// That's not really useful for a log.
One advantage of the macro, is that you could make your log output a bit more useful.
#define LOG(x) std::cout << x << '\n'
struct point { float x, y; };
// usability is better, but still limited,
point p{};
LOG("x: " << p.x << ", y: " << p.y);
// which gives this output.
x: 0, y: 0
That's a bit better, you are using a macro, and you do have more control over the output, making your log more useful. But it puts some limitations on your code... For example, you may want, at a later date, to use a third party logging library, or write your own, but some calls to LOG() will have operators in them, and this may force you to rewrite them.
For this reason, among others, a function template would be better, one that accepts any number of arguments.
template <typename... Args>
inline void LOG(Args&&... args)
{
(std::cout << ... << args) << '\n';
}
point p{};
LOG("x: ", p.x, ", y: ", p.y);
// which gives this output.
x: 0, y: 0
If you want to defeat logging in your release version, I suggest using a macro.
#define LOG(...)
// on MSVC
#define LOG(...) __noop
I wouldn't use #1 (macro version) unless you want to log the symbol name of the variable in the output, such as:
#define LOG(x) std::cout << #x << " = " << x << '\n'
I believe #2 and #4 are equivalent, as using auto introduces a template type under the hood.
#3 is slightly inferior as it requires you to write a declaration in a header file as well as putting the definition in a source file (since it is not inline), which is more code to maintain.
Consider, for example:
#include <array>
#include <iostream>
int main()
{
using Ram_bank = std::array<char, 0x2000>;
std::cout << "Size of ram bank is: " << Ram_bank::size() << '\n';
return 0;
}
Obviously this is not valid code, as Ram_bank is not an actual type or object but an alias. But, is there some way to achieve this? Is there a way to get the size of an aliased type?
Your code is not failing because Ram_bank is an alias. It is failing because size() is non-static and you would need an instance to call it on. Kosta's answer is an example of that.
Alternatively, you can use std::tuple_size:
std::cout << "Size of ram bank is: " << std::tuple_size<Ram_bank>::value << '\n';
You could instantiate an array and then take it's size (since std::array::size is a non-static member function). Every half-decent compiler should optimize this away:
std::cout << "Size of ram bank is: " << Ram_bank().size() << '\n';
Hello I have implemented an AST visitor using clang. It can correctly detect whenever a variable is declared, but sometimes it returns the wrong type for the variable. For example if a variable is declared as size_t or char32_t or even george it returns its type as int.
My code is here:
virtual bool VisitVarDecl(VarDecl *var)
{
numVariables++;
string varName = var->getQualifiedNameAsString();
string varType = var->getType().getAsString();
cout << "VisitVarDecl: " << varName << " of type " << varType << "\n";
APIs << varType << ", ";
return true;
}
Anyone knows why?
I would like my code to identify any variable declaration but even with an imaginary type such as test i; george x;
Thank you
When I tried my own implementation of type traits, I compared my results with std <type_traits>. I tried to check type traits of type float (int) const, which I thought should be function. I got strange results, so I tried to pass this type to std type traits. Here is my test code:
std::cout << std::is_function<float (int) const>::value;
std::cout << std::is_compound<float(int) const>::value;
std::cout << std::is_pointer<float(int)const>::value;
std::cout << std::is_class<float(int)const>::value;
std::cout << std::is_union<float(int)const>::value;
std::cout << std::is_member_pointer<float(int)const>::value;
std::cout << std::is_array<float(int)const>::value;
std::cout << std::is_scalar<float(int)const>::value;
std::cout << std::is_enum<float(int)const>::value;
std::cout << std::is_object<float(int)const>::value;
Output of this test was following:
0100000001
Meaning, that this type is compound & object, but not scalar. According to http://www.cplusplus.com/reference/type_traits/, it should be class, union or array, none of which is true. What should be correct result for this type? I am using MSVC 2015.
This is a bug in the MSVS implementation; float(int) const is both function and compound.
Raise it on Connect, if it's not already there (which it doesn't seem to be).
I suspect the trailing const (which is supposed to be ignored/stripped) is throwing things off.
I have a function that takes an ostream reference as an argument, writes some data to the stream, and then returns a reference to that same stream, like so:
#include <iostream>
std::ostream& print( std::ostream& os ) {
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print( std::cout ) << std::endl;
}
The output of this code is:
How are you?
Hello, world!0x601288
However, if I separate the chaining expressions into two statements, like this
int main() {
std::cout << "Hello, world!";
std::cout << print( std::cout ) << std::endl;
}
then I at least get the proper order in the output, but still get a hex value:
Hello, world! How are you?
0x600ec8
I would like to understand what's going on here. Does a normal function take precedence over operator<<, and that's why the output order reverses? What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
The behavior of your code is unspecified as per the C++ Standard.
Explanation
The following (I removed std::endl for simplicity)
std::cout << "Hello, world!" << print( std::cout );
is equivalent to this:
operator<<(operator<<(std::cout, "Hello, World!"), print(std::cout));
which is a function call, passing two arguments:
First argument is : operator<<(std::cout, "Hello, World!")
Second argument is : print(std::cout)
Now, the Standard doesn't specify the order in which arguments are evaluated. It is unspecified. But your compiler seems to evaluate the second argument first, that is why it prints "How are you?" first, evaluating the second argument to a value of type std::ostream& which then gets passed to the call shown above (that value is the object std::cout itself).
Why hexadecimal output?
You get hexadecimal output because the second argument evaluates to std::cout, which is being printed as hexadecimal number, because std::cout implicitly converts into pointer value of void* type, which is why it is printed as hexadecimal number.
Try this:
void const *pointer = std::cout; //implicitly converts into pointer type!
std::cout << std::cout << std::endl;
std::cout << pointer << std::endl;
It will print the same value for both. For example, this example at ideone prints this:
0x804a044
0x804a044
Also note that I didn't use explicit cast; rather std::cout is implicitly converted into pointer type.
Hope that helps.
What is the proper way to write a function that inserts data into an ostream but that can also chain with operator<<?
When it depends on what you mean by chaining? Obviously, the following wouldn't work (as explained above):
std::cout << X << print(std::cout) << Y << Z; //unspecified behaviour!
No matter how you write print().
However this is well-defined:
print(std::cout) << X << Y << Z; //well-defined behaviour!
The reason is that your print() function will be evaluated before the rest of the statement and return a reference to cout which is then actually printed as a pointer (cout << cout). This order of evaluation is actually unspecified behavior, but seems to be the case with your compiler.
As for defining a stream aware "function" that actually has defined behavior with the same functionality, this would work;
#include <iostream>
template <class charT, class traits>
std::basic_ostream<charT,traits>& print ( std::basic_ostream<charT,traits>& os )
{
os << " How are you?" << std::endl;
return os;
}
int main() {
std::cout << "Hello, world!" << print << std::endl;
}
See also this answer for a little more detail on what "unspecified" actually means in this case.
Hexadecimal Output
Before C++11, the class std::ostream has a conversion function to void*. Since your print function returns std::ostream&, when evaluating std::cout << print(...), the returned std::ostream lvalue will be implicitly converted to void* and then be outputted as a pointer value. This is why there is a hexadecimal output.
Since C++11, this conversion function is replaced by an explicit conversion function to bool, so trying to output an std::ostream object becomes ill-formed.
Evaluation Order
Before C++17, overloaded operator is considered a function call for analyzing evaluation order, and evaluation order of different arguments of a function call is unspecified. So it is not strange that the print function is evaluated firstly, which causes How are you? is outputted firstly.
Since C++17, the evaluation order of operands of operator << is strictly from left to right, and operands of overloaded operator share the same evaluation order as those of the bulit-in one (see more details here). So your program will always get the output (assume print returns something able to be outputted)
Hello, world! How are you?
something returned by print
LIVE EXAMPLE
In your statement std::cout << "Hello, world!" << print( std::cout ) << std::endl it's undefined whether std::cout << "Hello, world!" happens before or after print( std::cout ). That's why the order may not be what you expect.
The hex value comes from the fact that you're also doing std::cout << std::cout (print returns std::cout which is fed into the << chain). The right hand std::cout is converted to a void * and that's printed to the output.
This would work, to combine print with << and control the order:
print( std::cout << "Hello, world!" ) << std::endl;
Or, if you want a function that's called with <<, see Joachim's answer.