I have a cpp file as follows:
#include <iostream>
#include "i.h"
using namespace std;
typedef struct abc{
int a1;
int b1;
} abc_t, *abc;
void fun(abc x){
cout<<x->a1;
}
int main(){
abc val;
fun(val);
return 0;
}
The i.h file :
struct abc;
void fff(struct abc);
When I am compiling the code following error occurs:
t.cpp:8: error: conflicting declaration ‘typedef struct abc* abc’
t.cpp:5: error: ‘struct abc’ has a previous declaration as ‘struct abc’
t.cpp: In function ‘void fun(abc)’:
t.cpp:11: error: base operand of ‘->’ has non-pointer type ‘abc’
If I save the cpp file as c file and compile using c compiler then everything works fine.
What is the issue with c++ compiler?
You've declared abc as both a struct and a pointer to a struct by using typedef. It's the same as doing:
struct abc {...};
typedef abc abc_t; // ok, abc_t is now an alias for abc
typedef abc *abc; // error
Skip the typedef, abc_t and *abc and use the class (with all members public per default) abc as-is.
i.h
struct abc {
int a1 = 0;
int b1 = 0;
};
void fun(const abc& x);
i.cpp
#include <iostream>
#include "i.h"
void fun(const abc& x) {
std::cout << x.a1 << "\n";
}
main.cpp
#include <iostream>
#include "i.h"
int main(){
abc val;
fun(val);
return 0;
}
In C, this:
struct abc
{
int a1;
int b1;
};
creates a type struct abc (roughly speaking), but not a type abc.
That's why you use the typedef trick to create a type we can use without having to write struct everywhere:
typedef struct abc{
int a1;
int b1;
} abc_t;
Now you have the type abc_t, too, which is the same as struct abc. There is still no type abc.
So when you add on the declaration of a pointer called abc, that's valid, as the name is not taken yet.
In C++, the original declaration creates a type named abc. There is no need for the typedef trick, and your declaration of a pointer called abc is invalid because the name abc is taken.
Solution
You can disambiguate your names (and de-obfuscate the code) like so:
struct abc
{
int a1;
int b1;
};
typedef struct abc abc_t;
abc_t* ptr_to_abc;
Or, if you are writing C++ and don't need C compat, just this:
struct abc
{
int a1;
int b1;
};
abc* ptr_to_abc;
This
struct abc;
in C++ declares the type struct abc as well as the type abc, which then clashes with typedef'ing ...*abc again.
In C it just declares struct abc, so typedef'ing ...*abc does not produce a duplicate declaration.
Related
I have two structs A and B that live in the same namespace. For architectural and compatibility reasons I want to have A accessible through B.
I tried the following which is not working:
#include <iostream>
struct A
{
static void print()
{
std::cout << "hello SO!" << std::endl;
}
};
struct B
{
typedef A A; // error here
};
int main()
{
B::A::print();
return 0;
}
Apparently the typedef to the same name is not working. With g++ I get the following error:
foo.cpp:13:15: error: declaration of ‘typedef struct A B::A’ [-fpermissive]
typedef A A;
^
foo.cpp:3:8: error: changes meaning of ‘A’ from ‘struct A’ [-fpermissive]
struct A
It would work if I give it an other name (e.g. typedef A A2) but I want it to keep the same name.
Interestingly, it is actually working when I compile with clang but I would need code that also builds with gcc.
Is there some way to achieve this (i.e. being able to do B::A::print())?
I am currently using C++11 but going to a newer version might be possible if it is necessary.
just use typedef ::A A or using A = ::A
https://godbolt.org/z/VVKk3V
Here is a solution:
#include <iostream>
namespace NS {
struct A {
static void print() { std::cout << "hello SO!" << std::endl; }
};
struct B {
using A = NS::A;
};
} // namespace NS
int main() {
NS::B::A::print();
return 0;
}
Compiles fine.
Here's my code, and the IDE is DEV C++11
#include<iostream>
using namespace std;
class A{
public:
int a=15;
};
class B:public A
{
};
int main(){
int A::*ptr=&B::a; //OK
int B::*ptr1=&A::a; //why?
int B::A::*ptr2=&B::a;//why?
int B::A::*ptr3=&A::a; //why?
}
I have read Programming Languages — C++ and I know the type of &B::a is int A::*, but I don't realise why the next three lines will pass the compilation.
And the weirdest thing to me is the syntax of int B::A::* , what's the meaning of this? I'm just a newcomer of C/C++, so please tolerate my weird question.
Diagram representation may help you understand why it is ok and compiles
Interesting will be once you reinitialize the same variable in inherited class
#include<iostream>
using namespace std;
class A {
public:
int a = 15;
};
class B :public A
{
public:
int a = 10;
};
int main() {
int A::*ptr = &B::a; //Waring class B a value of type int B::* cannot be
//used to initialize an entity of type 'int A::*'
int B::*ptr1 = &A::a; // why?
int B::A::*ptr2 = &B::a;//Waring class B a value of type int B::* cannot
// be used to initialize an entity of type 'int A::*'
int B::A::*ptr3 = &A::a; //why?
}
I'm reading code of a C++ project and it contains some code of the following form:
namespace ns {
class A {};
class B {};
}
struct C {
typedef ns::A* ns::B::* type;
};
Can someone explain the meaning of the typedef line? type seems to be some kind of pointer to member of ns::B which points to ns::A, but I'm not sure.
Class A and B in the real code are not empty, but I think it's not relevant here. And here is a live example.
ns::B::*
is a pointer-to-member-variable of B. Then ns::A* is its type.
So the whole declaration means
pointer-to-member-variable of B of type ns::A*
The answer by #vsoftco already answers the core of the question. This answer shows how one might use such a typedef.
#include <iostream>
#include <cstddef>
namespace ns {
struct A {};
struct B
{
A* a1;
A* a2;
};
}
struct C {
typedef ns::A* ns::B::*type;
};
int main()
{
C::type ptr1 = &ns::B::a1;
C::type ptr2 = &ns::B::a2;
ns::B b1;
b1.*ptr1 = new ns::A; // Samething as b1.a1 = new ns::A;
return 0;
}
I am trying to figure out if there's any known pattern/idiom in c++ for what I am trying to do here. Class A must be composed of an object that has a function whose argument must also be of type A. The following code doesn't compile since typeid may not be used in a constant expression. Any suggestions?
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; }
};
class A {
B<typeid(A)> b;
};
int main()
{
A k;
}
Your stated requirements don't need templates at all, just a forward declaration:
#include <iostream>
class A; // forward declare A
struct B {
int f(A &i); // declaration only, definition needs the complete type of A
};
class A {
B b;
};
int B::f(A &i) { std::cout << "Hello\n"; } // define f()
int main()
{
A k;
}
You are looking for B<A> b; The following program compiles without error or warning on g++ 4.4.3.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; return 0; }
};
class A {
public:
B<A> b;
};
int main()
{
A k;
return k.b.f(k);
}
Note: If you are using templates only to avoid forward declaration, my solution is wrong. But, I'll leave it here in case you are using templates for some other legitimate reason.
I have a quick question about namespace scope:
I have two namespaces, A and B, where B is nested inside A.
I declare some typedefs inside A.
I declare a class inside B ( which is inside A )
To access the typedefs (declared in A), from inside B, do I need to do "using namespace A;"
ie:
B.hpp:
using namespace A;
namespace A {
namespace B {
class MyClass {
typedeffed_int_from_A a;
};
}
}
This seems redundant... Is this correct?
To access the typedefs (declared in A), from inside B, do I need to do "using namespace A;"
No.
However if there is a typedef or some other symbol with same name as your typedef, defined in the namespace B, then you need to write this:
A::some_type a;
Lets do a simple experiment to understand this.
Consider this code: (must read the comments)
namespace A
{
typedef int some_type; //some_type is int
namespace B
{
typedef char* some_type; //here some_type is char*
struct X
{
some_type m; //what is the type of m? char* or int?
A::some_type n; //what is the type of n? char* or int?
};
void f(int) { cout << "f(int)" << endl; }
void f(char*) { cout << "f(char*)" << endl; }
}
}
int main() {
A::B::X x;
A::B::f(x.m);
A::B::f(x.n);
return 0;
}
Output:
f(char*)
f(int)
That proves that type of m is char* and type of n is int as expected or intended.
Online Demo : http://ideone.com/abXc8
No, you don't need a using directive; as B is nested inside of A, the contents of A are in scope when inside B.