|
Thread Rules 1. This is not a "do my homework for me" thread. If you have specific questions, ask, but don't post an assignment or homework problem and expect an exact solution. 2. No recruiting for your cockamamie projects (you won't replace facebook with 3 dudes you found on the internet and $20) 3. If you can't articulate why a language is bad, don't start slinging shit about it. Just remember that nothing is worse than making CSS IE6 compatible. 4. Use [code] tags to format code blocks. |
On March 29 2014 16:31 Blisse wrote: Ah right I forgot about auto being old since unique succeeded it, but I don't see how that relates to not using C++ exceptions.
Google's explanation seemed to be countered by the fact that you could use smart pointers but Google didn't use them initially so they don't support them when maintaining legacy code. So I still don't see why you shouldn't be using C++ exceptions if you're smart about it. Well, the SO post says that exceptions are perfectly fine if your C++ code is solid. If you're dealing with bad C++ code, you're kinda screwed. No matter how good your new code is, old code can crash or leak if you hand it an exception.
|
ohhh oops I thought you were the one that said don't use C++ exceptions (that was RoyGBiv) :3 my bad, good to know, all that makes sense.
do you guys know what kind of things i can do to get more experience building embedded things? like building a robot and stuff like that. i hear about arduino and raspi, so i think i'll look at that. anything else you guys have tried?
|
type id to integer and back again
a template tale by nunez
the hype:
templates are awesome. templates employ types. templates, types, battlestar galactica.
if we (me-process, you-process) could talk in types we could use static polymorphism to hammer out responses. our kernel don't know shit about our type-vocabulary, so what's the fastest way to talk in types? here's a wild stab in the dark, which is exactly what will happen to you if you point out any flaws in my approach. we asume we talk in types that only carry semantics and no data, and denote a purely semantic type like that an id. it would be eejy peejy to modify this to accept data as well.
the usual suspects:
all of the following reside in the namespace AUX.
a list of types:
template<class... ts> struct tl{}; alleged shorthand for calling a type metafunction:
template<class u> using T=typename u::t; alleged shorthand for calling a value metafunction:
template<class t> constexpr decltype(t::v) V(){ return t::v; } alleged shorthand for getting the length of a list of types (lets assume length does what it's supposed to):
template<class T> constexpr int N(){ return V<length<T>>(); } alleged shorthand for extracting the index of a type in a typelist (lets assume idx_in does what it's supposed to):
template<class t,class T> constexpr int I(){ return V<idx_in<t,T>>(); }
the conversation id
in the quest of talking fast in type ids i will establish a quick framework. first and foremost a concept of a conversation will be defined, with a simple id that denotes some conversation. this is only defined in your mind, as this is the topmost layer of abstraction, your entry point.
struct nunez{};
the vocabulary:
to generate the necessary tools we need to know what type ids (or msg ids) are being talked in in this nunez conversation. establish a type-trait in the namespace GUT like so:
template<class convo_id,class=void> struct vocab{ static_assert(sizeof(convo)==0,"vocab not defined for convo"); };
with a cursory static check, no default behavior makes sense for a conversation! a implicit assumption is that the message ids are unique and provided as a nested typedef'ed type t in a typelist fashion:
typedef tl<msg_id0,msg_id1,...,msg_idn> t; it would be fairly trivial to make it explicit by making sure t is a typelist and any one of the types in the typelist is unique whenever the vocab's nested type t is used, but i will spare you in the name of terseness.
the message id as integer:
now we have the vocabulary with its type ids. what is the most apt way of sending this type from me to you? an semi-educated guess would be an unsigned integer as small as can be, given the number of types in our conversation. given s types indexed from 0 to (s-1), this is hopefully a way of finding the smallest uint to represent them (in the namespace AUX):
struct least{};
template<class... ts> struct uint_h{ static_assert(sizeof...(ts)<0,"AUX uint_h error"); };
template<int s> struct uint_h<least,idx<s>>{ typedef conditional_t< s<=256, //2^8 uint_least8_t, conditional_t< s<=65536, //2^16 uint_least16_t, conditional_t< s<=4295976296, uint_least32_t, uint_least64_t > > > t; };
template<class property,int bits> using uint_t=T<uint_h<property,idx<bits>>>;
template<int bits> using uint_least_t=uint_t<least,bits>; the 'least' awkwardness due to future expansion. thus we can define an apt message ingteger type given a conversation id and its vocabulary in the namespace GUT:
template<class convo_id> using msg_t=uint_least_t<N<T<vocab<convo_id>>>()>;
the mux
so far we have and id representing a conversation, the corresponding vocabulary of the conversation as well as what we hope is an apt integer type for carrying the message id from me to yue. here comes the convertion from message id to message integer in the namespace GUT:
template<class convo_id> struct mux{ template<class msg_id> static constexpr msg_t<convo_id> a(){ return I<msg_id,T<vocab<convo_id>>>(); } }; as well as a convenience function in the global namespace (it might as well just be a function):
template<class convo_id,class msg_id> constexpr GUT::msg_t<convo_id> mux(){ return GUT::mux<convo_id>::template a<msg_id>(); }
the intermezzo
ah halfway there, but the dragon's roar is yet but a whisper. we have a way of defining a conversation, with corresponding vocabulary, and a way for translating a message into a fitting integer. we have a to, but what's the fro? what's an apt mechanism for receiving an int and forwarding it as a msg id again? enter function spaces.
the function space
take a template function and a list of types, for each type in the typelist, instantiate the function with the given type, and store the function pointer in an array. now residing at the ith index of the array is a function pointer to the former template function instantiated with the ith type in the typelist. voila, you got your function space (it works for type-coordinates too).
the function trait
ok, so we identify with each convo a function that we will use to generate a function space:
template<class convo_id,class=void> struct fn{ static_assert(sizeof(convo_id)==0,"fn not defined"); }; the implicit assumption is that this trait will define the type of the instantiated function as a nested typedef t as well as a static template member function a that takes a msg_id as input and provides a function pointer of the type t as output.
we also provide the convenience alias template to extract the function type:
template<class convo_id> using fn_t=T<fn<convo_id>>;
sweet. now lets get to the juiciest and hariest bit.
the demux
to tie it all together we now will define the fro.
it consists of an array of funtion pointers, whose type is defined in the function trait, instantiated with the message ids defined in the vocab trait. the type of the array is denoted F_t, and the array itself F.
this array will be generated by a nested helper class called gen defined as templated on a parameter pack to enable in class specialization without a dummy parameter. the demux class will aslo provide a static member function that takes a fitting integer msg as input and outputs the corresponding function pointer.
template<class convo_id> struct demux{ typedef std::array< fn_t<convo_id>, N<T<vocab<convo_id>>>() > F_t;
static const F_t F;
template<class... ts> struct gen{ static_assert(sizeof...(ts)<0,"GUT gen error"); };
template<class... msgs> struct gen<tl<msgs...>>{ static F_t a(){ return {fn<convo_id>::template a<msgs>()... }; } };
static fn_t<convo_id> const& a(msg_t<convo_id> msg){ return F[msg]; } };
initalizing the array for every convo calling gen's a instantiated with its messages.
template<class convo_id> typename demux<convo_id>::F_t const demux<convo_id>::F( demux<convo_id>::gen<T<vocab<convo_id>>>::a() );
all of it in the namespace GUT. cherry on top a convenience function demux in global namespace:
template<class convo_id> GUT::fn_t<convo_id> demux(GUT::msg_t<convo_id> msg){ return GUT::demux<convo_id>::a(msg); }
the end
and so we have a way of defining a type conversation, it's type vocabulary, a translation from a type to a fitting integer and back again to a function instantiated with the given type that can be called at your pleasure.
on the talking end the message id is resolved into an integer at compile time, while at the receiving end it amounts to a lookup to retreive the message id from the integer.
the example
a trivial example where we just talk with ourself in process memory.
we define the conversation id
struct nunez{}; the message ids
struct team{}; struct liquid{}; struct dot{}; struct net{}; the function template
template<class msg_id> void f(){} template<> void f<team>(){ std::cout<<"this is team"; } template<> void f<liquid>(){ std::cout<<"liquid"; } template<> void f<dot>(){ std::cout<<'.'; } template<> void f<net>(){ std::cout<<"net\n"; } the specialization of the convo to the framework in the namespace GUT
template<> struct vocab<nunez>{ typedef tl<team,liquid,dot,net> t; };
template<> struct fn<nunez>{ typedef void(*t)(); template<class msg> static t a(){ return &f<msg>; } };
a global message queue and functions to send and receive messages from to the convo
typedef std::queue< GUT::msg_t<nunez> > msg_q_t;
msg_q_t m;
void snd(GUT::msg_t<nunez> msg){ m.push(msg); }
GUT::msg_t<nunez> rcv(){ auto msg=m.front(); m.pop(); return msg; }
and the program sending team,liquid,dot,net after muxing them to ints receiving them and calling the function correspoding to the demuxed message:
int main(){ snd(mux<nunez,team>()); snd(mux<nunez,liquid>()); snd(mux<nunez,dot>()); snd(mux<nunez,net>()); while(m.size()) demux<nunez>(rcv())(); }
the output
[jeh@gimli aux]$ make g++ -c -std=c++0x -I. -Wfatal-errors -I.. main.cpp g++ -o main main.o rm -rf *.o [jeh@gimli aux]$ ./main this is teamliquid.net
src
feedback / comments welcome. it was made to solve the problem of sending simple semantic messages from one process to another through sockets and kernel message queues, all of the different messages and their specific callsites known at compile time.
|
Newline shouldn't be a part of "net" template - big part of magic behind semantic ideas and templates is the fact that you can mix and match them in various ways to achieve different meaning, conveying the end of something should be a template in itself. Dot shouldn't be a string but a char.
|
I'm surprised I still understand most of this despite not actually having written any C++ in years.
Sometimes I really miss templates in C#... So powerful!
|
On March 30 2014 06:42 Manit0u wrote: Newline shouldn't be a part of "net" template - big part of magic behind semantic ideas and templates is the fact that you can mix and match them in various ways to achieve different meaning, conveying the end of something should be a template in itself. Dot shouldn't be a string but a char.
ah thx, i'm wasn't quite sure how string/char literals work, excellent catch. a byte here, a byte there!
code
std::cout<<"literal: "<<'.'<<" size: "<<sizeof('.')<<" type: "<<to_string<decltype('.')>()<<std::endl; std::cout<<"literal: "<<"."<<" size: "<<sizeof(".")<<" type: "<<to_string<decltype(".")>()<<std::endl; output
literal: . size: 1 type: [char] literal: . size: 2 type: [char [2]] the example is poorly chosen, and the behaviour of the 'receiving function' as well as the messages are arbitrary, there just to showcase the concept of the type -> integer -> type framework. where type->integer mux is a metafunction (compile time) and integer->type demux is a constant time lookup runtime in template function-space.
On March 30 2014 07:02 spinesheath wrote: I'm surprised I still understand most of this despite not actually having written any C++ in years.
Sometimes I really miss templates in C#... So powerful!
yes, and so much you don't know you don't know. wow, much explore, many possibilities, such T. this code is terse and quirky. so maybe a bad indicator even.
|
On March 29 2014 06:10 gOst wrote: Hello everyone. This is my first time posting is this thread so please be gentle. I will soon start my third year on a bachelor of software development, major in CS and I was thinking of getting into developing APIs. I'm half decent with C++ and Java and have dabbled somewhat in Python as well. Is there any career what so ever in developing APIs? Is there some particular skill/knowledge that could be useful? Good API design is a very difficult challenge, read some books on the subject and see if it's for you. There are a few companies that I've interviewed with over the past couple months that are almost exclusively API driven development shops. TwitchTV is one of them.
API driven development can lead to very clean decoupled modular applications working together to solve a larger problem, and Twitch's business needs are just that. The chat engine is a separate application, as is the web interface for browsing and viewing streams. They interact with each other through their APIs, allowing them to be updated asynchronously leading to easier maintenance/development. If business needs are not being solved by this engineering approach then no reason to try to solve your problem with tools that make your job harder in the end or hurt the business.
|
I was wondering if it's ok to type:
if (instance == null) { return; }
instead of:
if (instance == null) { return; }
What is usually the norm?
Edit: the above C++ code looks complex and a bit unreadable. Maybe it's C++'s fault. I just think Java is a lot easier.
|
On March 30 2014 20:27 darkness wrote:I was wondering if it's ok to type: if (instance == null) { return; }
instead of: if (instance == null) { return; }
What is usually the norm? Edit: the above C++ code looks complex and a bit unreadable. Maybe it's C++'s fault. I just think Java is a lot easier. If you do that, you usually would just write
if (instance == null) return;
Of course there also is:
if (instance == null) return;
I personally prefer:
if (instance == null) { return; }
Also if this is C/C++, you should prefer:
if (null == instance)
In any case, there's no real norm to that. Just do it consistently.
Templates have this habit of being hard to read. To compensate, they're extremely powerful.
|
and use nullptr if that's a pointer and it's c++! yes, the code is (probably) relatively complex, and my careless coding isn't doing you any favors. i would go for spinesheaths first option personally, so terse.
|
Oh right, nullptr. Just shows that I've not been writing any C++ code.
|
On March 30 2014 20:27 darkness wrote:I was wondering if it's ok to type: if (instance == null) { return; }
instead of: if (instance == null) { return; }
What is usually the norm? Edit: the above C++ code looks complex and a bit unreadable. Maybe it's C++'s fault. I just think Java is a lot easier. Typical style guidelines would say
if (null == instance) { return }
The reason for null == <var> here is that instance is already the context when reading, so you read it as 'if null return' which is easier for people to read. The reason you leave the block there even though it's a one-liner is that if you were to add another operation before the return you'd end up with a cleaner diff which makes code reviews easier. This one is debatable, and if you have a pattern of one-liner conditionals you'd probably make an exception case for those use cases.
|
I find
if(null == instance) a lot harder to read. The reason for writing it like this is C/C++'s implicit pointer to bool conversion which screws you over if you accidentally write only a single '='.
|
On March 30 2014 21:04 spinesheath wrote:If you do that, you usually would just write if (instance == null) return;
Of course there also is: if (instance == null) return;
NOOOOOOOOOO never do this. Never never never. Always do what you prefer here:
On March 30 2014 21:04 spinesheath wrote:I personally prefer: if (instance == null) { return; }
This is the reason:
Your code in Year X:
if (fooConditional) doThing();
... Your code sits around for 2-3 years
Your code in Year X + 3 after someone modifies it along with a whole bunch of other code:
if (fooConditional) doFirstThing(); doThing();
Extreme badness ensues. For the most recent catastrophic example, see Apple's bug which compromised SSL/TLS in OSX and iOS: http://opensource.apple.com/source/Security/Security-55471/libsecurity_ssl/lib/sslKeyExchange.c
(oop, go to line 631 there, bit far down)
Ideally you have stuff set up to catch this, such that missing { } after if () is not allowed.
|
if you one line statements you are a horrible person and should be burned at the stake :<
also if you don't use braces when it's optional to use them you should be burned at your local bbq :>
|
It's coding standard where I work. I argued against it, but who listens to the newbie?
That Apple bug is hilarious.
|
so you write it like this:
if(the_bloob) do_the_bleeb();
so terse, impossible to misunderstand! and adding on another call writes itself:
if(the_bloob) do_the_bleeb(),and_the_bluub();
|
You did overload operator,() there, didn't you?
|
I have to implement a graph shortest path algorithm for homework. I finished it and works fine but I ran into a problem i'm still perplexed by any explaination would be nice VS2010
I have this function used internally during the algorithm that gets a node based on the id. If it currently does not exist it creates one with default values (not visited, infinite distance, etc) then returns the iterator to that.
std::vector<GraphNode>::iterator graph::get_node(std::string id, std::vector<GraphNode>& nodes) { for(auto i = nodes.begin(); i != nodes.end(); ++i) { if(i->node_id == id) { return i; } } GraphNode gn(id); nodes.push_back(gn); return get_node(id, nodes); }
So thats the working version, notice the recursion.
However this does not work
std::vector<GraphNode>::iterator graph::get_node(std::string id, std::vector<GraphNode>& nodes) { for(auto i = nodes.begin(); i != nodes.end(); ++i) { if(i->node_id == id) { return i; } } GraphNode gn(id); nodes.push_back(gn); return nodes.rbegin().base(); }
Using the returned iterator throws asserts?! It should always be valid. i just push_backed a element so rbegin() should always be valid calling base on that just turns a reverse_iterator into a regular one.
So i'm pretty lost of why this fails.
|
On March 31 2014 03:21 spinesheath wrote:You did overload operator,() there, didn't you? of course! that's always the first thing i do when i define a class.
@amnesty(woops) your code works on my puter. uh well when it finds one it does.
std::reverse_iterator::base
Returns the underlying base iterator.
The base iterator refers to the element that is next to the element the reverse_iterator is currently pointing to. That is std::reverse_iterator(it).base() == std::next(it). src
ok so since you push_back() and do rbegin(), that is the last element. the base() of that will give you the next element of the last element, that is std::end(nodes):
std::vector::end, std::vector::cend
Returns an iterator to the element following the last element of the container.
This element acts as a placeholder; attempting to access it results in undefined behavior. src you can use (--it), since this is the last element. either do
return --nodes.rbegin().base(); or be careful when you use it, or simplest just
return nodes.back();
|
|
|
|
|
|