I have a header file like the below -
// abc.hpp
#include <vector>
#include <string>
namespace A
{
namespace B
{
struct abc
{
std::string _type;
};
using abc_vector = std::vector<abc>;
}
}
I am using forward declaration in another header file.
// con.hpp
#include <vector>
namespace A
{
namespace B
{
struct abc; // Forward Declaration
using abc_vector = std::vector<abc>;
}
namespace C
{
class N
{
public:
B::abc_vector foo(std::string type);
};
}
}
What really confuses me is that my code compiles and works.
How is the vector allowed to be declared with incomplete type?
I think that it shouldn't be able to decide the size of abc.
using abc_vector = std::vector<abc>;
The below is the code I used to test my header files.
Strange enough, that it compiles and works all fine.
#include "con.hpp"
#include "abc.hpp"
#include <iostream>
namespace A
{
namespace C
{
B::abc_vector N::foo(std::string type)
{
B::abc a;
a._type = type;
B::abc_vector d;
d.push_back(a);
return d;
}
}
}
int main()
{
A::C::N n;
auto container = n.foo("test");
for (const auto& i : container)
std::cout << i._type << ' ';
return 0;
}
The code line
using abc_vector = std::vector<abc>;
only introduces a type alias for std::vector<abc>. That doesn't require, by any means, the size of abc since no object of type abc is allocated at all. Only a new type is declared.
B::abc_vector d;
Indeed needs the definition of abc. Nevertheless it works because at this point abc already has been defined because the header file abc.hpp has been included.
You are referring to this answer, where
std::vector<B> v;
is "done." This is not the same as what you did. You just introduced a type alias. std::vector<B> v; actually defines a variable. Therefore the definition of B is mandatory.
Note that
using abc_vector = std::vector<abc>;
is equivalent to
typedef std::vector<abc> abc_vector;
Maybe this makes it a bit clearer why the size of abc isn't necessary to know at this time point in compilation.
This is an interesting topic (at least to me) and applies to other std containers.
Originally the standard made it undefined behaviour to instantiate a container of an incomplete type. However implementations did not disallow it. This was in all likelihood not deliberate, but merely a side-effect of the fact that elements in (for example the vector) are stored in a memory location that is referenced by a pointer.
Thus the size of an element does not need to be known until an element is actually required - during the instantiation of a member function of the vector.
Here is a starting point for research if you'd like to explore further:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4056.html
There is an interesting observation. Both GCC5.2 and CLANG3.6 compile following code.
struct A;
std::vector<A> my_func(); //Definition of my_func is in some CPP file
But throw errors for
struct A;
std::vector<A> v;
And reasoning for this is size of vector won't change for different type it is holding. See following code snippet.
struct B{int i; int j;};
struct C{int a,b,c;};
std::vector<B> pp;
std::vector<C> qq;
int main()
{
std::cout<<sizeof(pp)<<'\n';
std::cout<<sizeof(qq)<<'\n';
}
Output
24
24
But for std::vector<A> v it has to provide the Allocator<A>() as well. And allocator required members of struct A like constructor, copy constructor, destructor etc.
Also one important thing to note here is pointer arithmetic for incomplete type is not allowed.
If you see the errors thrown by CLANG, it clearly says same.
In file included from /tmp/gcc-explorer-compiler115920-68-1xsb8x7/example.cpp:2:
In file included from /usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/vector:64:
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:161:9: error: arithmetic on a pointer to an incomplete type 'A'
- this->_M_impl._M_start); }
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/../../../../include/c++/4.9/bits/stl_vector.h:253:7: note: in instantiation of member function 'std::_Vector_base<A, std::allocator<A> >::~_Vector_base' requested here
vector()
^
Everything else is quite straight forward.
Following is a typedef , so compiler does need to know about size.
using abc_vector = std::vector<abc>;
So, the code structure discussed in question is good to go ahead with.
Related
This question already has an answer here:
How can I declare a member vector of the same class?
(1 answer)
Closed 5 years ago.
Why is the following code valid? The struct test contains a vector of test, so that the following code compiles (IDEOne):
#include <iostream>
#include <vector>
using namespace std;
struct test {
vector<test> a;
};
int main() {
// your code goes here
test t;
if (t.a.size() > 0)
return -1;
else if (t.a[0].a[0].a.size() > 0)
return 1;
return 0;
}
How does the compiler handle the struct so that is is possible to test for t.a[0].a[0].a.size()? Is there a limit on how often I could repeat the .a[0]?
Edit: This questions has an answer that claims this is undefined behaviour: Are C++ recursive type definitions possible, in particular can I put a vector<T> within the definition of T?
=> This is confusing
=> perhaps my question is a duplicate
This boils down to vector<T> not needing to know the size a value of type T occupies, which allows T to be an incomplete type. Essentially, the mechanism in play here is the same as in this declaration:
struct test {
test* start;
test* end;
};
The compiler has no problem declaring pointers to any type, as long as you promise to define it at some later point.
This behavior changes based on the template: you have no problem defining test with a vector<T>, but an array<T,Size> or even a pair<T,K> would be problematic:
struct broken1 {
array<broken1,3> a; // Does not compile
};
struct broken2 {
pair<broken2,broken2> p; // Does not compile
};
I want to use a Boost.TypeErasure any<...> object as a polymorphic function object.
However, I can't figure out how to rebind it (like I could with std::function).
The following example code doesn't compile.
#include <boost/type_erasure/any.hpp>
#include <boost/type_erasure/callable.hpp>
using namespace boost::type_erasure;
namespace mpl = boost::mpl;
struct A { void operator()(int){} void operator()(double){} };
struct B { void operator()(int){} void operator()(double){} };
int main(int argc, const char * argv[])
{
A a; B b;
any < mpl::vector <
callable<void(int)>,
callable<void(double)>,
copy_constructible<>
>> x = a, y = b;
x = y; // rebind x to b, doesn't compile
return 0;
}
When compiled with clang-3.5 -std=c++11, I got this error
/opt/local/include/boost/type_erasure/any.hpp:1083:9: error: no matching member function for call to
'_boost_type_erasure_assign_impl'
_boost_type_erasure_assign_impl(
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Quoting from the usage documentation, emphasis on what relaxed enables:
The main class in the library is any. An any can store objects that
meet whatever requirements we specify. These requirements are passed
to any as an MPL sequence.
any<mpl::vector<copy_constructible<>, typeid_<>, relaxed> > x(10);
int i = any_cast<int>(x); // i == 10
copy_constructible is a builtin concept that allows us to copy and
destroy the object. typeid_ provides run-time type information so
that we can use any_cast. relaxed enables various useful defaults.
Without relaxed, any supports exactly what you specify and
nothing else. In particular, it allows default construction and
assignment of any.
I'm trying to implement a minheap in C++. However the following code keeps eliciting errors such as :
heap.cpp:24:4: error: cannot convert 'complex int' to 'int' in assignment
l=2i;
^
heap.cpp:25:4: error: cannot convert 'complex int' to 'int' in assignment
r=2i+1;
^
heap.cpp: In member function 'int Heap::main()':
heap.cpp:47:16: error: no matching function for call to 'Heap::heapify(int [11], int&)'
heapify(a,i);
^
heap.cpp:47:16: note: candidate is:
heap.cpp:21:5: note: int Heap::heapify(int)
int heapify(int i) //i is the parent index, a[] is the heap array
^
heap.cpp:21:5: note: candidate expects 1 argument, 2 provided
make: * [heap] Error 1
#include <iostream>
using namespace std;
#define HEAPSIZE 10
class Heap
{
int a[HEAPSIZE+1];
Heap()
{
for (j=1;j<(HEAPISZE+1);j++)
{
cin>>a[j];
cout<<"\n";
}
}
int heapify(int i) //i is the parent index, a[] is the heap array
{
int l,r,smallest,temp;
l=2i;
r=2i+1;
if (l<11 && a[l]<a[i])
smallest=l;
else
smallest=i;
if (r<11 && a[r]<a[smallest])
smallest=r;
if (smallest != i)
{
temp = a[smallest];
a[smallest] = a[i];
a[i]=temp;
heapify(smallest);
}
}
int main()
{
int i;
for (i=1;i<=HEAPSIZE;i++)
{
heapify(a,i);
}
}
}
Ultimately, the problem with this code is that it was written by someone who skipped chapters 1, 2 and 3 of "C++ for Beginners". Lets start with some basics.
#include <iostream>
using namespace std;
#define HEAPSIZE 10
Here, we have included the C++ header for I/O (input output). A fine start. Then, we have issued a directive that says "Put everything that is in namespace std into the global namespace". This saves you some typing, but means that all of the thousands of things that were carefully compartmentalized into std:: can now conflict with names you want to use in your code. This is A Bad Thing(TM). Try to avoid doing it.
Then we went ahead and used a C-ism, a #define. There are times when you'll still need to do this in C++, but it's better to avoid it. We'll come back to this.
The next problem, at least in the code you posted, is a misunderstanding of the C++ class.
The 'C' language that C++ is based on has the concept of a struct for describing a collection of data items.
struct
{
int id;
char name[64];
double wage;
};
It's important to notice the syntax - the trailing ';'. This is because you can describe a struct and declare variables of it's type at the same time.
struct { int id; char name[64]; } earner, manager, ceo;
This declares a struct, which has no type name, and variables earner, manager and ceo of that type. The semicolon tells the compiler when we're done with this statement. Learning when you need a semicolon after a '}' takes a little while; usually you don't, but in struct/class definition you do.
C++ added lots of things to C, but one common misunderstanding is that struct and class are somehow radically different.
C++ originally extended the struct concept by allowing you to describe functions in the context of the struct and by allowing you to describe members/functions as private, protected or public, and allowing inheritance.
When you declare a struct, it defaults to public. A class is nothing more than a struct which starts out `private.
struct
{
int id;
char name[64];
double wage;
};
class
{
public:
int id;
char name[64];
double wage;
};
The resulting definitions are both identical.
Your code does not have an access specifier, so everything in your Heap class is private. The first and most problematic issue this causes is: Nobody can call ANY of your functions, because they are private, they can only be called from other class members. That includes the constructor.
class Foo { Foo () {} };
int main()
{
Foo f;
return 0;
}
The above code will fail to compile, because main is not a member of Foo and thus cannot call anything private.
This brings us to another problem. In your code, as posted, main is a member of Foo. The entry point of a C++ program is main, not Foo::main or std::main or Foo::bar::herp::main. Just, good old int main(int argc, const char* argv[]) or int main().
In C, with structs, because C doesn't have member functions, you would never be in a case where you were using struct-members directly without prefixing that with a pointer or member reference, e.g. foo.id or ptr->wage. In C++, in a member function, member variables can be referenced just like local function variables or parameters. This can lead to some confusion:
class Foo
{
int a, b;
public:
void Set(int a, int b)
{
a = a; // Erh,
b = b; // wat???
}
};
There are many ways to work around this, but one of the most common is to prefix member variables with m_.
Your code runs afoul of this, apparently the original in C passed the array to heapify, and the array was in a local variable a. When you made a into a member, leaving the variable name exactly the same allowed you not to miss the fact that you no-longer need to pass it to the object (and indeed, your heapify member function no-longer takes an array as a pointer, leading to one of your compile errors).
The next problem we encounter, not directly part of your problem yet, is your function Heap(). Firstly, it is private - you used class and haven't said public yet. But secondly, you have missed the significance of this function.
In C++ every struct/class has an implied function of the same name as the definition. For class Heap that would be Heap(). This is the 'default constructor'. This is the function that will be executed any time someone creates an instance of Heap without any parameters.
That means it's going to be invoked when the compiler creates a short-term temporary Heap, or when you create a vector of Heap()s and allocate a new temporary.
These functions have one purpose: To prepare the storage the object occupies for usage. You should try and avoid as much other work as possible until later. Using std::cin to populate members in a constructor is one of the most awful things you can do.
We now have a basis to begin to write the outer-shell of the code in a fashion that will work.
The last change is the replacement of "HEAPSIZE" with a class enum. This is part of encapsulation. You could leave HEAPSIZE as a #define but you should expose it within your class so that external code doesn't have to rely on it but can instead say things like Heap::Size or heapInstance.size() etc.
#include <iostream>
#include <cstdint> // for size_t etc
#include <array> // C++11 encapsulation for arrays.
struct Heap // Because we want to start 'public' not 'private'.
{
enum { Size = 10 };
private:
std::array<int, Size> m_array; // meaningful names ftw.
public:
Heap() // default constructor, do as little as possible.
: m_array() // says 'call m_array()s default ctor'
{}
// Function to load values from an istream into this heap.
void read(std::istream& in)
{
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
}
return in;
}
void write(std::ostream& out)
{
for (size_t i = 0; i < Size; ++i)
{
if (i > 0)
out << ','; // separator
out << m_array[i];
}
}
int heapify(size_t index)
{
// implement your code here.
}
}; // <-- important.
int main(int argc, const char* argv[])
{
Heap myHeap; // << constructed but not populated.
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
myHead.write(std::cout);
return 0;
}
Lastly, we run into a simple, fundamental problem with your code. C++ does not have implicit multiplication. 2i is the number 2 with a suffix. It is not the same as 2 * i.
int l = 2 * i;
There is also a peculiarity with your code that suggests you are mixing between 0-based and 1-based implementation. Pick one and stick with it.
--- EDIT ---
Technically, this:
myHeap.load(std::cin); // read from cin
for (size_t i = 1; i < myHeap.Size; ++i)
{
myHeap.heapify(i);
}
is poor encapsulation. I wrote it this way to draw on the original code layout, but I want to point out that one reason for separating construction and initialization is that it allows initialization to be assured that everything is ready to go.
So, it would be more correct to move the heapify calls into the load function. After all, what better time to heapify than as we add new values, keeping the list in order the entire time.
for (size_t i = 0; i < Size; ++i)
{
in >> m_array[i];
heapify(i);
}
Now you've simplified your classes api, and users don't have to be aware of the internal machinery.
Heap myHeap;
myHeap.load(std::cin);
myHeap.write(std::cout);
My declaration is as follows
#include <vector>
#include <iostream>
using namespace std;
typedef struct _ListofHops_T
{
int macAddrLtr;
int ttlValue;
}ListofHops;
struct ReadActivateLinkTrace
{
typedef std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
int main()
{
ReadActivateLinkTrace readLinkTrace;
for (size_t listItr=0; listItr < readLinkTrace.ListofHopsList.size(); listItr++)
{
.....
}
}
I am trying to declare a vector of list of hops struct within a struct ReadActivateLinkTrace.
Is the above declaration valid.
I get the following error compiling
vector.cpp:23: error: invalid use of
ReadActivateLinkTrace::ListofHopsList
I am new to vectors . how can i acess/iterate through vector of structures defined in a structure?
The declaration is valid, but it doesn't do what you think. ListofHopsList is a type (hint: typedef), not a variable. You're probably looking for
struct ReadActivateLinkTrace
{
std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
The problem wasn't with the vector itself, but with the fact that you weren't declaring a member, but defining a new type.
Also, is there any reason you're using a vector of pointers as opposed to a vector of objects?
ReadActivateLinkTrace::ListofHopsList is a typedef, which only declares an alias for a name of a type. It does not define an actual object of that type. You apparently want:
struct ReadActivateLinkTrace
{
std::vector < ListofHops *> ListofHopsList;
bool operationState;
};
You should probably have some second thoughts about that being a vector of pointers though. At least offhand, it doesn't seem very likely that a pointer is the best choice here. While you're at it, this:
typedef struct _ListofHops_T
{
int macAddrLtr;
int ttlValue;
}ListofHops;
Is pretty horrible in a couple of ways. First the typedef here is only needed in C code, not C++. Second, the name _ListofHops_T is reserved for the implementation, so using it gives undefined behavior. This should be just:
struct ListofHops {
int macAddrLtr;
int ttlValue;
};
I have the following code which works as expected:
#include <iostream>
using namespace std;
typedef int (TMyFunc)(int);
TMyFunc* p;
int x(int y)
{
return y*2;
}
int main()
{
p = &x;
cout << (*p)(5) << endl;
}
What I want to do is skip defining x and define p there straight. Something like
TMyFunc p; p(y){return y*2;}.
Is that possible? If so how do I do it? If not why?
EDIT:
After seeing the answers, I think I should clarify: I want the definition to be separate. i.e. function definition will be in a shared object. An application will acquire a function pointer to the function via dlsym. I do not want a function object. What I want is to know if I can define a function using its type which a header file common to both the shared object and the application will provide. I hope that came out right :).
EDIT2: For sbi :)
This resides in a header which is included in both the application and the shared object:
#define FNAME_GET_FACTORY "GetFactory"
#define FNAME_GET_FUNCTION_IDS "GetFunctionIDs"
#define FNAME_GET_PLUGIN_INFO "GetPluginInfo"
typedef FunctionFactory* (*TpfGetFactory)();
typedef size_t (*TpfGetFunctionIDs)(int**);
typedef PluginInfo* (*TpfGetPluginInfo)();
In the application, something like this happens:
TpfGetFactory pF = (TpfGetFactory)dlsym(pHandle, FNAME_GET_FACTORY);
//Use pF for anything
Now, to do this, I have to define GetFactory as follows in the shared object:
extern "C" FunctionFactory* FNAME_GET_FACTORY(){//CODE}
Forgetting the extern "C" part for now, Can I define this function using the type TpfGetFactory which is already defined? (This is not a huge issue I know - but I am curious as to whether it is possible :) ). What I want is something like this in the shared object :
TpfGetFactory f;
f(){//Implementation}
EDIT3:
My try:
#include <iostream>
using namespace std;
typedef int (TF)(int);
TF f;
f(int x)
{
return x*2;
}
int main()
{
x(3);
}
main.cpp:9: error: ISO C++ forbids declaration of ‘f’ with no type
main.cpp: In function ‘int main()’:
main.cpp:16: error: ‘x’ was not declared in this scope
It's possible in C++1x, the next C++ standard, generally expected next year (which would make it C++11, then). It allows this:
auto p = [](int y){return y*2;};
This relies on auto been given a new meaning ("automatically deduce the type of this variable from the expression that initializes it") and the new lambda functions (allowing to create functions on the fly).
Your compiler might actually already support this.
This works fine for me, with the current C++03 Standard:
typedef int (TMyFunc)(int);
TMyFunc* p;
int test()
{
struct LocalClass
{
static int functionLocal(int y)
{
return 2;
};
};
LocalClass localClass;
p = &(LocalClass::functionLocal);
}
But maybe it happens to be more complicated to write than what you wanted to simplify ;-),
however it works and you can define your functions in place, locally.
Here is some documentation about local classes
This will be possible in the next C++ standard, via lambdas. In the current standard, however, it is impossible to define one function inside another.
Not directly in C++98.
For standard C++, that is C++98, check out e.g. the Boost Lambda library. It lets you write expressions like
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
C++0x adds direct support for lambda expressions.
Cheers & hth.,