Herb Sutter did it again:
Things Your Programming Language Never Told You
As he said himself, this is a must read for every modern programmer.
Nothing for me to add, just watch and be amazed...
Friday, October 26, 2007
Monday, October 22, 2007
Doxygen rules!
I'd like to give many thanks to Dimitri van Heesch, for his excellent programming tool : the Doxygen.
I finally got to add examples to Boost Logging Lib v2. Well, you can do some amazing things with doxygen:
Say you have a file which you want to use as an example:
/**
@example your_example_name.cpp
@copydoc your_example_name
@page your_example_name your_example_name.cpp Example
... (your documentation)
*/
Then, to reference the example's description, you'll do this:
/**
...
@copydoc your_example_name
...
*/
To create a page that will contain all the examples:
/**
@page all_examples All code examples
- @ref example_1
- @ref example_2
...
\n\n\n
@section example_1 My Example 1
@include example_1_source_file.cpp
\n\n\n
\n\n\n
@section example_2 My Example 2
@include example_2_source_file.cpp
\n\n\n
...
*/
The end result is really amazing. Check it out!
I finally got to add examples to Boost Logging Lib v2. Well, you can do some amazing things with doxygen:
Say you have a file which you want to use as an example:
- You can add the description within the example itself
- You can reference (link to) the example's description
- You can add the example to the "Examples" tab
- When clicking the example in the "Examples" tab, it will show its description
- You can even have a page which will contain the source code for all examples
/**
@example your_example_name.cpp
@copydoc your_example_name
@page your_example_name your_example_name.cpp Example
... (your documentation)
*/
Then, to reference the example's description, you'll do this:
/**
...
@copydoc your_example_name
...
*/
To create a page that will contain all the examples:
/**
@page all_examples All code examples
- @ref example_1
- @ref example_2
...
\n\n\n
@section example_1 My Example 1
@include example_1_source_file.cpp
\n\n\n
\n\n\n
@section example_2 My Example 2
@include example_2_source_file.cpp
\n\n\n
...
*/
The end result is really amazing. Check it out!
Friday, October 19, 2007
VS 2005 : It's great to get meaningful error messages...
When dealing with template programming, getting compiler errors can get pretty cryptic. However, VS 2005 did its best to help me:
(note: I replaced <> with { } - since the editor got pretty messed up)
(yes: the error is 5132 characters long)
1}mul_levels_one_logger.obj : error LNK2001: unresolved external symbol "struct boost::logging::detail::log_keeper{struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts},&struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts} & __cdecl g_l_boost_log_impl_(void)} g_l" (?g_l@@3U?$log_keeper@U?$logger@U?$process_msg@U?$return_str@V?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@ostream_like@gather@logging@boost@@U?$format_write@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@U?$simple@U?$remove_reference@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@boost@@@format_and_write@34@U?$simple@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@@msg_route@34@V?$shared_ptr_holder@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@V?$shared_ptr_holder@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@@writer@45@@logging@boost@@Uno_ts@filter@23@@logging@boost@@$1?g_l_boost_log_impl_@@YAAAU123@XZ@detail@logging@boost@@A)
(note: I replaced <> with { } - since the editor got pretty messed up)
(yes: the error is 5132 characters long)
1}mul_levels_one_logger.obj : error LNK2001: unresolved external symbol "struct boost::logging::detail::log_keeper{struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts},&struct boost::logging::logger{struct boost::logging::process_msg{struct boost::logging::gather::ostream_like::return_str{class std::basic_ostringstream{char,struct std::char_traits{char},class std::allocator{char} } },struct boost::logging::writer::format_write{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::format_and_write::simple{struct boost::remove_reference{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &} },struct boost::logging::msg_route::simple{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type} },class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32},class boost::logging::array::shared_ptr_holder{struct boost::logging::manipulator::base{class std::basic_string{char,struct std::char_traits{char},class std::allocator{char} } const &,struct boost::logging::manipulator::detail::default_type},class boost::logging::threading::mutex_win32} } },struct boost::logging::filter::no_ts} & __cdecl g_l_boost_log_impl_(void)} g_l" (?g_l@@3U?$log_keeper@U?$logger@U?$process_msg@U?$return_str@V?$basic_ostringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@ostream_like@gather@logging@boost@@U?$format_write@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@U?$simple@U?$remove_reference@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@boost@@@format_and_write@34@U?$simple@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@234@@msg_route@34@V?$shared_ptr_holder@U?$base@AAV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@V?$shared_ptr_holder@U?$base@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@Udefault_type@detail@manipulator@logging@boost@@@manipulator@logging@boost@@Vmutex_win32@threading@34@@array@34@@writer@45@@logging@boost@@Uno_ts@filter@23@@logging@boost@@$1?g_l_boost_log_impl_@@YAAAU123@XZ@detail@logging@boost@@A)
They must be using a group IQ...
Some company just thought that since copyright is such a cool thing, why not copyright as much as possible?
http://pubcit.typepad.com/clpblog/2007/10/you-hereby-agre.html
http://techdirt.com/articles/20071017/092927.shtml
Next thing, probably they'll copyright their javascript variable names...
http://pubcit.typepad.com/clpblog/2007/10/you-hereby-agre.html
http://techdirt.com/articles/20071017/092927.shtml
Next thing, probably they'll copyright their javascript variable names...
Thursday, October 18, 2007
The email hell...
First, there's spamming - we all get that (forgive the pun).
And we all find ways to deal with it - but it seems that every email server has its own twisted way of making sure the right email never gets to you.
For instance, mine (and I didn't know that), did an email check on the sender - if the sender email is invalid, the email doesn't get through.
Alrighty! That should be cool, right? Well, not really... Because being afraid of spam, a lot of users purposely obfuscate their email address - and I don't get their email. Oh well - lets say we forget that, and move on... But wait, there's more! Even legitimate users, with legitimate emails can get into trouble:
Email verification can be used by spammers, to see if an email exists or not. Now, ain't that cute? Sooo... some email servers decided to get smart, and not respond to email verification. Sounds pretty reasonable, right?
Now, lets see how a server that requests an email verification of the sender plays along with a server that does not respond to it. Well - not good at all: the former server tries several times, and the latter thinks it's spam. End result: an email coming from the latter server will never get through. Aaaaand: you (your ip, email, etc) will end up in the latter server's spam list.
That's what happened to an email I got from Charles Brockman - anyway, I think that's sorted out (even though I'm still on AT&T's spam list :P )
I had my email provider remove that sender email verification for my address. And just when I though I was out of problems, here's an email I got, when answering to someone else:
Oh well - back to the drawing board - I've emailed my provider - I'll get that "installed".
And we all find ways to deal with it - but it seems that every email server has its own twisted way of making sure the right email never gets to you.
For instance, mine (and I didn't know that), did an email check on the sender - if the sender email is invalid, the email doesn't get through.
Alrighty! That should be cool, right? Well, not really... Because being afraid of spam, a lot of users purposely obfuscate their email address - and I don't get their email. Oh well - lets say we forget that, and move on... But wait, there's more! Even legitimate users, with legitimate emails can get into trouble:
Email verification can be used by spammers, to see if an email exists or not. Now, ain't that cute? Sooo... some email servers decided to get smart, and not respond to email verification. Sounds pretty reasonable, right?
Now, lets see how a server that requests an email verification of the sender plays along with a server that does not respond to it. Well - not good at all: the former server tries several times, and the latter thinks it's spam. End result: an email coming from the latter server will never get through. Aaaaand: you (your ip, email, etc) will end up in the latter server's spam list.
That's what happened to an email I got from Charles Brockman - anyway, I think that's sorted out (even though I'm still on AT&T's spam list :P )
I had my email provider remove that sender email verification for my address. And just when I though I was out of problems, here's an email I got, when answering to someone else:
SMTP error from remote mail server after RCPT TO:<[...]@users.sf.net>:
host mail.sourceforge.net [66.35.250.206]: 550-Postmaster verification failed while checking [...]@torjo.com
550-Called: 72.52.140.12
550-Sent: RCPT TO:postmaster -at- torjo.com
550-Response: 550 No such email address
550-Several RFCs state that you are required to have a postmaster
550-mailbox for each mail domain. This host does not accept mail
550-from domains whose servers reject the postmaster address.
550 Sender verify failed
Oh well - back to the drawing board - I've emailed my provider - I'll get that "installed".
Sunday, October 14, 2007
Nigeria vs Bill Gates
This was one of those funnies - that you just can't believe could happen: Bill gates was denied visa for Nigeria.
The template< namespace> construct
2 days ago, I've discovered an interesting technique, which is equivalent to the
template< namespace> construct.
I will first show you an example, because talking about concepts combined with templates is kind of rough ;)
The need
I have a function 'write' - that can be overloaded for different types.
I have 3 namespaces in which this resides - and on each namespace, the meaning of 'write' is completely different:
template< namespace convert = prepend>
struct write_time {
template
void operator()(const msg_type & msg) {
...
convert::write(msg, src);
}
};
Why template< namespace> ?
Of course, it would be easy to have the same concept as a template< class>. However, I want other libs/client code to be able to overload my function, and my functor classes to still have the same default (convert_format::prepend).
The construct
The solutions is simple: just defer to a class which forwards to your namespace:
namespace convert_format {
namespace prepend {
void write(const string_type & src, string & dest) {
dest.insert( dest.begin(), src.begin(), src.end() );
}
template< class string> void write(const string_type & src, cache_string_one_str<> & dest) {
dest.prepend_string(src);
}
...
}}
struct do_convert_format {
struct prepend {
template< class string>
void write(const string_type & src, string & dest) {
convert_format::prepend::write(src, dest);
}
};
struct append { ... };
struct modify { ... };
};
When implementing my functor classes, I just use:
template< class convert = do_convert_format::prepend>
struct write_time { ... };
I've used this in my Boost Logging Lib v2 : here.
I'm sure someone has used this before. Is it documented anywhere else?
template< namespace> construct.
I will first show you an example, because talking about concepts combined with templates is kind of rough ;)
The need
I have a function 'write' - that can be overloaded for different types.
I have 3 namespaces in which this resides - and on each namespace, the meaning of 'write' is completely different:
- prepend - prepends a string
- append - appends a string
- modify - modifies a string
template< namespace convert = prepend>
struct write_time {
template
void operator()(const msg_type & msg) {
...
convert::write(msg, src);
}
};
Why template
Of course, it would be easy to have the same concept as a template
The construct
The solutions is simple: just defer to a class which forwards to your namespace:
namespace convert_format {
namespace prepend {
void write(const string_type & src, string & dest) {
dest.insert( dest.begin(), src.begin(), src.end() );
}
template< class string> void write(const string_type & src, cache_string_one_str<> & dest) {
dest.prepend_string(src);
}
...
}}
struct do_convert_format {
struct prepend {
template< class string>
void write(const string_type & src, string & dest) {
convert_format::prepend::write(src, dest);
}
};
struct append { ... };
struct modify { ... };
};
When implementing my functor classes, I just use:
template< class convert = do_convert_format::prepend>
struct write_time { ... };
I've used this in my Boost Logging Lib v2 : here.
I'm sure someone has used this before. Is it documented anywhere else?
Thursday, October 11, 2007
The mobile office - feedback
Have comments related to the Mobile office article?
Please post them here ;)
Please post them here ;)
Boost Logging v2 - with documentation
I've added quite a bit more cool things to the lib, and added documentation.
http://torjo.com/log2/
http://torjo.com/log2/doc/html/
Enjoy ;)
http://torjo.com/log2/
http://torjo.com/log2/doc/html/
Enjoy ;)
Wednesday, October 3, 2007
Boost Logging v2
Well, it's been a looooong time... But I'm back!
I'm developing the Boost Logging Lib v2 - Check it out!
Feedback is most welcome!
I'm developing the Boost Logging Lib v2 - Check it out!
Feedback is most welcome!
Tuesday, October 2, 2007
Tip: commenting variables/constants
For too many times, I see code like this:
// we allow only 100 words
int allow_word_count = 100;
// we allow only up to 10 users
const int MAX_USER_COUNT = 10;
What's wrong with the above?
A program should stay flexible in the face of change. How would you like to see:
// we allow only 100 words
int allow_word_count = 245;
Not very pleasant - but it happens. So, make your comments descriptive, while avoiding to use the actual value in the comment:
// we allow only this many words
int allow_word_count = 100;
// we allow only up to this many users
const int MAX_USER_COUNT = 10;
Much better!
// we allow only 100 words
int allow_word_count = 100;
// we allow only up to 10 users
const int MAX_USER_COUNT = 10;
What's wrong with the above?
A program should stay flexible in the face of change. How would you like to see:
// we allow only 100 words
int allow_word_count = 245;
Not very pleasant - but it happens. So, make your comments descriptive, while avoiding to use the actual value in the comment:
// we allow only this many words
int allow_word_count = 100;
// we allow only up to this many users
const int MAX_USER_COUNT = 10;
Much better!
Subscribe to:
Posts (Atom)