Preprocessor: concat previous line number in the name of a structure - c++

I know how to declare a struct where the name contains the current line number. The following code works as expected.
#define CREATE_NAME_CONCAT_(X, Y) X ## Y
#define CREATE_NAME_CONCAT(X, Y) CREATE_NAME_CONCAT_(X, Y)
#define CREATE_FOO_NAME CREATE_NAME_CONCAT(Foo_, __LINE__)
struct CREATE_FOO_NAME { int x; };
typedef Foo_4 Foo;
int main()
{
Foo foo;
foo.x = 42;
return 0;
}
How can I write the typedef line using the previous line number ? The following code doesn't work:
#define CREATE_NAME_CONCAT_(X, Y) X ## Y
#define CREATE_NAME_CONCAT(X, Y) CREATE_NAME_CONCAT_(X, Y)
#define CREATE_FOO_NAME CREATE_NAME_CONCAT(Foo_, __LINE__)
struct CREATE_FOO_NAME { int x; };
typedef CREATE_NAME_CONCAT(Foo_, __LINE__-1) Foo;
int main()
{
Foo foo;
foo.x = 42;
return 0;
}
Note 1: yes I have a good reason to do that
Note 2: I don't use C++11 or more recent
Note 3: I don't want to debate notes 1 & 2

The preprocessor is pretty limited, the best solution is to not use it at all. You can accomplish something similar with templates:
template <int>
struct FooT;
template <>
struct FooT<__LINE__> { int x; };
typedef FooT<__LINE__-1> Foo;
int main()
{
Foo foo;
foo.x = 42;
return 0;
}
I don't know if this meets your requirements as they seem to be secret.

Related

Forward declaration for struct and nested struct

Is any way to use forward declaration for struct X and Y which is nested as I I need to use them in the hpp for some of the class members, but I would like to have them in the cpp because my hpp is included in many places
Thank you so much for any help!
//F1.hpp
#ifndef F1_HPP_
#define F1_HPP_
struct X;
struct Y
{
struct Y1
{
int y1;
};
X x1;
};
class Y1
{
public:
void f(X x);
void f2(Y::Y1 y1);
};
#endif // F1_HPP_
//F1.cpp
#include "F1.hpp"
#include <iostream>
struct X
{
int x;
int x2;
int x3;
};
void Y1::f(X x)
{
std::cout<<"-1-\n";
}
// main.cpp
#include <iostream>
#include "F1.hpp"
using namespace std;
int main()
{
X x;
Y1 f1;
f1.f(x);
return 0;
}
Short Answer: No (as far as my c++ knowledge concern)
Why:
First, if you want to declare a variable of any type you need to know the exact size of the type. That is why forward declaration is not enough BUT pointers.
Because size of pointers are always the same no matter the data type, you can use forward declaration for pointers.
Nested Types:
As far as I know of C++ we can't nest types with just variables BUT pointers.
You can use pointers and forward declaration to nest types.
Maybe something like this:
struct Y
{
struct Y1
{
int y1;
};
X* x1;
};
class Y1
{
public:
void f(X* x);
void f2(Y::Y1* y1);
};
We cannot have a nonstatic data member of incomplete type. In particular, with only a forward declaration for X, we cannot define a data member of type X as you've done inside F1.hpp. This can be seen from type:
Any of the following contexts requires type T to be complete:
declaration of a non-static class data member of type T;
Better would be to create separate header and source file for each class and then include the header wherever needed/required as shown below:
Yfile.h
#ifndef F1_HPP_
#define F1_HPP_
#include "Xfile.h" //needed for X x1; data member
struct Y
{
struct Y1
{
int y1 = 0;
};
X x1;
};
#endif
Xfile.h
#ifndef X_H
#define X_H
#include <iostream>
struct X
{
int x = 0;
int x2 = 0;
int x3 = 0;
};
#endif
Y1file.h
#ifndef Y1_H
#define Y1_H
#include "Yfile.h"
//forward declarations for parameters
struct X;
class Y1
{
public:
void f(X x);
void f2(Y::Y1 y1);
};
#endif
Y1file.cpp
#include "Y1file.h"
#include "Xfile.h"
#include "Yfile.h"
void Y1::f(X x)
{
std::cout<<"-1-\n";
}
void Y1::f2(Y::Y1 y1)
{
std::cout<<"f2"<<std::endl;
}
main.cpp
#include "Xfile.h"
#include "Y1file.h"
int main()
{
X x;
Y1 f1;
f1.f(x);
return 0;
}
Working demo
The output of the above program is:
-1-

Is the use of `struct` well-defined in c++ function signatures?

This question is similar to, but more specific than, this other question:
using struct keyword in variable declaration in C++.
Consider the following program:
#include <stdio.h>
struct Foo {
int x;
int y;
};
Foo getFoo() {
Foo foo;
return foo;
}
int main(){
getFoo();
}
The above program compiles with g++ but not gcc.
We can modify the program as follows to make it compile with both gcc and g++:
#include <stdio.h>
struct Foo {
int x;
int y;
};
struct Foo getFoo() {
struct Foo foo;
return foo;
}
int main(){
getFoo();
}
Is this use of the struct keyword guaranteed by the standard to be well-defined in C++?
Yes. That's known as an elaborated-type-specifier.

Static declarations and definitions inside of function scope don't change?

Ok, on assigning a static variable declared in a constructor/function (I don't think it matters which) to a compile time defined value, it's as if the variables only been assigned once, see Example:
#include <iostream>
#define y 4
#define z 3
using namespace std;
class Foo
{
public:
Foo(int x)
{
static int i = x;
cout << i << endl;
}
};
int main()
{
Foo p(y);
Foo o(z);
return 0;
}
Expected output:
4
3
Actual output:
4
4
I couldn't find anything on searching, though if this is a dupe just let me know and i'll close the question.
A static local variable is initialized only once when the function it resides in is entered for the first time. So only the first initialization happens, and all further ones are ignored.
Here's your program, modified to illustrate it.
#include <iostream>
#define y 4
#define z 3
using namespace std;
struct Bar {
int i;
Bar(int i) : i{i}
{
cout << "Bar::Bar with " << i << '\n';
}
};
class Foo
{
public:
Foo(int x)
{
static Bar b = x;
cout << b.i << '\n';
}
};
int main()
{
Foo p(y);
Foo o(z);
return 0;
}
If you want each subsequent call to modify i, you need to assign into it:
static int i; // default initialize i.
i = x; // assign a new value into i

c++ create dynamic type

I have the following situation: Depending on some parameter that my function takes it have to create different types:
I want to do something like this:
if(variant==1){
#define my_type int;
}
else{
#define my_type double;
}
cout<<sizeof(my_type);
and then use my_type in my further code.
So, that in case of variant=1 sizeof(my_type) gives 4 and for variant=2 it gives 8.
How can this be done? Either in this manner or another.
Thanks.
I agree with #Magnus Hoff in that what you asked cannot be done. But there are two approximations.
Option 1: make variant a macro.
#ifdef variant
# define my_type int
#else
# define my_type double
#endif
Option 2: use template function.
Instead of
void func(int variant) {
if (variant==1)
#define my_type int
else
#define my_type double
my_type ...
}
do this:
template<typename my_type> void func() {
my_type ...
}
Replace this:
if(variant==1){
#define my_type int;
}
else{
#define my_type double;
}
cout<<sizeof(my_type);
… with this:
template< class Type >
void foo()
{
// ...
cout<<sizeof(Type);
}
// ...
if( variant==1 )
{
foo<int>();
}
else
{
foo<double>();
}
Note that a runtime value can't affect compile time decisions. Without a time travel device.

Can a macro accept a list-initialization as argument?

Any work around to make the below code work? it currently give the following error:
error: too many arguments provided to function-like macro invocation
X({1,2,3});
^
code:
#include <stdio.h>
#define X(a) a,
int main()
{
mystruct = X({1,2,3}));
}
I tried something with templates but so far I know (I'm a bit new to C++) templates aren't "powerful" enough to implement something like the X macro. As you may already noticied, what I'm looking for is implement something like the X macro. Others ideas to do this are very welcome too as long as everything is know at compile-time.
This does the trick:
#define X(...) __VA_ARGS__
struct mystruct {
int a,b,c;
};
int main() {
mystruct s = X({1,2,3});
}
Or as a variation:
#define X(...) {__VA_ARGS__}
struct mystruct {
int a,b,c;
};
int main() {
mystruct s = X(1,2,3);
}