Académique Documents
Professionnel Documents
Culture Documents
with C++
Code, Culture, Context and Change
Kevlin Henney
kevlin@curbralan.com
Agenda
• Intent
Some observations on agile development with C++
• Content
C++ development
Culture shock
Accidental complexity
Dependency management
Memetic engineering
In closing
XP Day 06 2
C++ Development
One reason that life is complex is that it has a real part and an imaginary part.
Andrew Koenig
XP Day 06 3
Characterising C++
XP Day 06 4
C++ Systems
XP Day 06 5
XP Day 06 6
Agility and C++
Culture Shock
Design and programming are human activities; forget that and all is lost.
Bjarne Stroustrup
XP Day 06 8
Culture Can Decelerate Change
• Cleverness is valued
Template metaprogramming, preprocessor abuse,
cunning bit twiddling, micro-optimisation, etc
• BUFD or 'design' by wizard
Design horizons are typically distant or overlooked
• Testing is somebody else's problem
Debugging is seen as the typical response to defects
• Maintenance does not involve refactoring
Automated refactoring tools are not widespread
XP Day 06 10
Some Possibilities for Change
Accidental Complexity
XP Day 06 12
Complexity Can Decelerate Change
XP Day 06 13
Criticality of Knowledge
XP Day 06 15
Sufficient Knowledge
class access_control
{
public:
bool is_locked(const std::string &key) const
{
return locked.count(key) != 0;
}
bool lock(const std::string &key)
{
return locked.insert(key).second;
}
bool unlock(const std::string &key)
{
return locked.erase(key);
}
...
private:
std::set<std::string> locked;
...
};
XP Day 06 16
The Bad, the Ugly, and the Good
XP Day 06 17
#ifndef BOOST_LEXICAL_CAST_INCLUDED typename stringstream<CharType>::type interpreter(arg); &>::do_cast(arg); // mpl::apply_if doesn't work well for MSVC 6 here, and neither does
#define BOOST_LEXICAL_CAST_INCLUDED #endif } // inheriting from a metafunction
// Boost lexical_cast.hpp header -------------------------------------------// setup_interpreter<Target, Source>(interpreter); template<typename CharType, typename CharTraits, typename Allocator, typename Source> template<class Target, class Source>
// inline std::basic_string<CharType, CharTraits, Allocator> struct select_base
// See http://www.boost.org for most recent version including documentation. Target result; lexical_cast_impl(std::basic_string<CharType, CharTraits, Allocator> *, Source arg) {
// { typedef typename mpl::if_<is_same<Target, char>, // Target==char?
// what: lexical_cast custom keyword cast if(!(interpreter >> result) || !(interpreter >> std::ws).eof()) return any_to_string_base<std::basic_string<CharType, CharTraits, Allocator>, Source, typename mpl::if_<is_same<Source, char>, // Source==char?
// who: contributed by Kevlin Henney and enhanced by Terje Slettebø throw detail::no_lexical_conversion<Target, Source>(); CharType>::do_cast(arg); direct_cast_base<Target, Source>,
// when: November 2000, March 2003 } typename mpl::if_<is_same<Source, char *>, // Source==char *?
return result; pointer_to_char_to_char_base<Target, Source>,
#include <typeinfo> } template<typename CharType, typename CharTraits, typename Allocator> typename mpl::if_<is_same<Source, const char *>, // Source==const char *?
#include <string> }; inline std::basic_string<CharType, CharTraits, Allocator> pointer_to_char_to_char_base<Target, Source>,
#include <boost/config.hpp> lexical_cast_impl(std::basic_string<CharType, CharTraits, Allocator> *, CharType arg) typename mpl::if_<is_same<Source, std::string>, // Source==std::string?
#include <boost/limits.hpp> ////////////////////////////////////////////////////////////////////////// { string_to_char_base<Target, const Source &>,
#include <boost/static_assert.hpp> // any_to_string_base return char_to_string_base<std::basic_string<CharType, CharTraits, Allocator>, CharType>::do_cast(arg); lexical_cast_base<Target, Source, char>
////////////////////////////////////////////////////////////////////////// } >::type
#ifdef BOOST_NO_STRINGSTREAM >::type
#include <strstream> template<typename Target, typename Source, typename CharType> template<typename CharType, typename CharTraits, typename Allocator> >::type
#else struct any_to_string_base inline std::basic_string<CharType, CharTraits, Allocator> >::type,
#include <sstream> { lexical_cast_impl(std::basic_string<CharType, CharTraits, Allocator> *, CharType *arg) typename mpl::if_<is_same<Target, std::string>, // Target==std::string?
#endif static Target do_cast(Source arg) { typename mpl::if_<is_same<Source, char>, // Source==char?
{ return direct_cast_base<std::basic_string<CharType, CharTraits, Allocator>, CharType *>::do_cast(arg); char_to_string_base<Target, Source>,
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || \ typename stringstream<CharType>::type interpreter; } typename mpl::if_<is_same<Source, char *>, // Source==char *?
defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) setup_interpreter<Target, Source>(interpreter); direct_cast_base<Target, Source>,
#include <boost/mpl/if.hpp> if(!(interpreter << arg)) template<typename CharType, typename CharTraits, typename Allocator> typename mpl::if_<is_same<Source, const char *>, // Source==const char *?
#include <boost/type_traits/same_traits.hpp> throw detail::no_lexical_conversion<Target, Source>(); inline std::basic_string<CharType, CharTraits, Allocator> direct_cast_base<Target, Source>,
#endif return interpreter.str(); lexical_cast_impl(std::basic_string<CharType, CharTraits, Allocator> *, const CharType *arg) typename mpl::if_<is_same<Source, std::string>, // Source==std::string?
} { direct_cast_base<Target, const Source &>,
namespace boost }; return direct_cast_base<std::basic_string<CharType, CharTraits, Allocator>, const CharType any_to_string_base<Target, Source, char>
{ *>::do_cast(arg); >::type
// exception used to indicate runtime lexical_cast failure template<typename Target, typename Source> } >::type
class bad_lexical_cast : public std::bad_cast struct string_to_char_base >::type
{ { template<typename Target> >::type,
public: static Target do_cast(Source arg) inline Target lexical_cast_impl(Target *, char *arg) typename mpl::if_<is_same<Target, wchar_t>, // Target==wchar_t?
virtual ~bad_lexical_cast() throw() { { typename mpl::if_<is_same<Source, wchar_t>, // Source==wchar_t?
{ if(arg.length()!=1) return string_to_any_base<Target, char *, char>::do_cast(arg); direct_cast_base<Target, Source>,
} throw detail::no_lexical_conversion<Target, Source>(); } typename mpl::if_<is_same<Source, wchar_t *>, // Source==wchar_t *?
}; return arg[0]; pointer_to_char_to_char_base<Target, Source>,
} template<typename Target> typename mpl::if_<is_same<Source, const wchar_t *>, // Source==const wchar_t *?
namespace detail }; inline Target lexical_cast_impl(Target *, const char *arg) pointer_to_char_to_char_base<Target, Source>,
{ { typename mpl::if_<is_same<Source, std::wstring>, // Source==std::wstring?
template<typename Target, typename Source> template<typename Target, typename Source> return string_to_any_base<Target, const char *, char>::do_cast(arg); string_to_char_base<Target, const Source &>,
class no_lexical_conversion : public bad_lexical_cast struct pointer_to_char_to_char_base } lexical_cast_base<Target, Source, wchar_t>
{ { >::type
public: static Target do_cast(Source arg) template<typename Target> >::type
no_lexical_conversion() { inline Target lexical_cast_impl(Target *, wchar_t arg) >::type
: description( if(arg[0] == Target() || arg[1] != Target()) { >::type,
std::string() + "bad lexical cast: " + throw detail::no_lexical_conversion<Target, Source>(); return lexical_cast_base<Target, wchar_t, wchar_t>::do_cast(arg); typename mpl::if_<is_same<Target, std::wstring>, // Target==std::wstring?
"source type value could not be interpreted as target, Target=" + return arg[0]; } typename mpl::if_<is_same<Source, wchar_t>, // Source==wchar_t?
typeid(Target).name() + ", Source=" + typeid(Source).name()) } char_to_string_base<Target, Source>,
{ }; template<typename Target> typename mpl::if_<is_same<Source, wchar_t *>, // Source==wchar_t *?
} inline Target lexical_cast_impl(Target *, wchar_t *arg) direct_cast_base<Target, Source>,
virtual ~no_lexical_conversion() throw() template<typename Target, typename Source> { typename mpl::if_<is_same<Source, const wchar_t *>, // Source==const wchar_t *?
{ struct char_to_string_base return string_to_any_base<Target, wchar_t *, wchar_t>::do_cast(arg); direct_cast_base<Target, Source>,
} { } typename mpl::if_<is_same<Source, std::wstring>, // Source==std::wstring?
virtual const char *what() const throw() static Target do_cast(Source arg) direct_cast_base<Target, const Source &>,
{ { template<typename Target> any_to_string_base<Target, Source, wchar_t>
return description.c_str(); return Target(1, arg); inline Target lexical_cast_impl(Target *, const wchar_t *arg) >::type
} } { >::type
private: }; return string_to_any_base<Target, const wchar_t *, wchar_t>::do_cast(arg); >::type
const std::string description; // static initialization fails on MSVC6 } >::type,
}; template<typename Target, typename Source> typename mpl::if_<is_same<Target, Source>, // Target==Source?
} struct direct_cast_base template<typename Target, typename CharType, typename CharTraits, typename Allocator> direct_cast_base<Target, const Source &>,
{ inline Target lexical_cast_impl(Target *, const std::basic_string<CharType, CharTraits, Allocator> &arg) typename mpl::if_<is_same<Source, char *>, // Source==char *?
namespace detail static Target do_cast(Source arg) { string_to_any_base<Target, Source, char>,
{ { return string_to_any_base<Target, typename mpl::if_<is_same<Source, const char *>, // Source==const
template<typename CharType> return arg; const std::basic_string<CharType, CharTraits, Allocator> &, CharType>::do_cast(arg); char *?
struct stringstream } } string_to_any_base<Target, Source, char>,
{ }; typename mpl::if_<is_same<Source, std::string>, //
#if defined(BOOST_NO_STRINGSTREAM) template<typename Type> Source==std::string?
typedef std::strstream type; #if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && \ inline Type lexical_cast_impl(Type *, const Type &arg) string_to_any_base<Target, const Source &, char>,
#else !defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) { typename mpl::if_<is_same<Source, wchar_t>, // Source==wchar_t?
typedef std::basic_stringstream<CharType> type; return direct_cast_base<Type, const Type &>::do_cast(arg); lexical_cast_base<Target, Source, wchar_t>,
#endif template<typename Target, typename Source> } typename mpl::if_<is_same<Source, wchar_t *>, // Source==wchar_t
}; inline Target lexical_cast_impl(Target *, Source arg) *?
{ inline std::string lexical_cast_impl(std::string *, char *arg) lexical_cast_base<Target, Source, wchar_t>,
template<typename Target, typename Source, typename Interpreter> return lexical_cast_base<Target, Source, char>::do_cast(arg); { typename mpl::if_<is_same<Source, const wchar_t *>, // Source==const
void setup_interpreter(Interpreter &interpreter) } return direct_cast_base<std::string, char *>::do_cast(arg); wchar_t *?
{ } lexical_cast_base<Target, Source, wchar_t>,
interpreter.unsetf(std::ios_base::skipws); template<typename Target, typename Source> typename mpl::if_<is_same<Source, std::wstring>, //
void lexical_cast_impl(Target **,Source) inline std::string lexical_cast_impl(std::string *, const char *arg) Source==std::wstring?
if(std::numeric_limits<Target>::is_specialized) { { lexical_cast_base<Target, const Source &, wchar_t>,
interpreter.precision(std::numeric_limits<Target>::digits10 + 1); BOOST_STATIC_ASSERT((Target **) 0); // Pointer as target type not supported return direct_cast_base<std::string, const char *>::do_cast(arg); lexical_cast_base<Target, Source, char>
else if(std::numeric_limits<Source>::is_specialized) } } >::type
interpreter.precision(std::numeric_limits<Source>::digits10 + 1); >::type
} inline char lexical_cast_impl(char *, char *arg) inline std::string lexical_cast_impl(std::string *, const std::string &arg) >::type
{ { >::type
template<typename Target, typename Source, typename CharType> return pointer_to_char_to_char_base<char, char *>::do_cast(arg); return direct_cast_base<std::string, const std::string &>::do_cast(arg); >::type
struct lexical_cast_base } } >::type
{ >::type
static Target do_cast(Source arg) inline char lexical_cast_impl(char *, const char *arg) inline std::wstring lexical_cast_impl(std::wstring *, wchar_t *arg) >::type
{ { { >::type
typename stringstream<CharType>::type interpreter; return pointer_to_char_to_char_base<char, const char *>::do_cast(arg); return direct_cast_base<std::wstring, wchar_t *>::do_cast(arg); >::type
} } >::type
setup_interpreter<Target, Source>(interpreter); >::type type;
template<typename Source> inline std::wstring lexical_cast_impl(std::wstring *, const wchar_t *arg) };
Target result; inline wchar_t lexical_cast_impl(wchar_t *, Source arg) {
{ return direct_cast_base<std::wstring, const wchar_t *>::do_cast(arg);
if(!(interpreter << arg) || !(interpreter >> result) || return lexical_cast_base<wchar_t, Source, wchar_t>::do_cast(arg); } template<typename Target, typename Source>
!(interpreter >> std::ws).eof()) } inline Target lexical_cast_impl(Target *, Source arg)
throw detail::no_lexical_conversion<Target, Source>(); inline std::wstring lexical_cast_impl(std::wstring *, const std::wstring &arg) {
inline wchar_t lexical_cast_impl(wchar_t *, wchar_t *arg) { return select_base<Target, Source>::type::do_cast(arg);
return result; { return direct_cast_base<std::wstring, const std::wstring &>::do_cast(arg); }
} return pointer_to_char_to_char_base<wchar_t, wchar_t *>::do_cast(arg); } #endif
}; } }
inline wchar_t lexical_cast_impl(wchar_t *, wchar_t arg)
////////////////////////////////////////////////////////////////////////// inline wchar_t lexical_cast_impl(wchar_t *, const wchar_t *arg) { template<typename Target, typename Source>
// string_to_any_base { return direct_cast_base<wchar_t, wchar_t>::do_cast(arg); inline Target lexical_cast(const Source &arg)
////////////////////////////////////////////////////////////////////////// return pointer_to_char_to_char_base<wchar_t, const wchar_t *>::do_cast(arg); } {
} return detail::lexical_cast_impl(static_cast<Target *>(0), arg);
template<typename Target, typename Source, typename CharType> inline std::wstring lexical_cast_impl(std::wstring *, wchar_t arg) }
struct string_to_any_base inline wchar_t lexical_cast_impl(wchar_t *, const std::wstring &arg) { }
{ { return char_to_string_base<std::wstring, wchar_t>::do_cast(arg);
static Target do_cast(Source arg) return string_to_char_base<wchar_t, const std::wstring &>::do_cast(arg); } // Copyright Kevlin Henney, 2000-2003, Terje Slettebø, 2003. All rights reserved.
{ } //
#ifdef BOOST_NO_STRINGSTREAM #else // Permission to use, copy, modify, and distribute this software for any
typename stringstream<CharType>::type interpreter; template<typename CharType, typename CharTraits, typename Allocator> // purpose is hereby granted without fee, provided that this copyright and
inline CharType // Simulated partial specialisation // permissions notice appear in all copies and derivatives.
if(!(interpreter << arg)) lexical_cast_impl(CharType *, const std::basic_string<CharType, CharTraits, Allocator> &arg) // select_base //
throw detail::no_lexical_conversion<Target, Source>(); { ////////////////////////////////////////////////////////////////////////// // This software is provided "as is" without express or implied warranty.
#else return string_to_char_base<CharType, const std::basic_string<CharType, CharTraits, Allocator> #endif
XP Day 06 19
XP Day 06 20
Dependency Management
XP Day 06 21
Lightweight Headers
XP Day 06 24
Inheritance Tax
Interface Classes
XP Day 06 26
Memetic Engineering
XP Day 06 27
Decluttering
class command class command
{ {
public: public:
void execute() virtual void execute() = 0;
{ virtual void rollback() = 0;
do_execute(); virtual ~command();
} };
void rollback()
{
class command_processor
do_rollback();
{
}
public:
virtual ~command();
void execute(command *);
private:
void rollback();
virtual void do_execute() = 0; ...
virtual void do_rollback() = 0; };
};
class command_processor
{
public:
void execute(command *);
void rollback();
...
};
XP Day 06 30
Deglobalisation
XP Day 06 31
In Closing
The only thing to do with good advice is to pass it on. It is never any use to oneself.
Oscar Wilde
XP Day 06 32
Taming Complexity