Re: Is run-time switching on type traits bad?
Nick Hounsome wrote:
On 15 Apr, 07:53, DeMarcus <use_my_alias_h...@hotmail.com> wrote:
Hi,
Is run-time switching on type traits as bad as switching on class type?
(Sutter & Alexandrescu, C++ Coding Standards, Item 90 - Avoid type
switching)
I.e. should type traits be for compile time only?
A run-time example:
class VisitableInterface
{
public:
virtual ~VisitableInterface() {}
virtual void accept( Visitor& v ) const = 0;
virtual bool isPOD() const = 0;
};
template<typename T>
class SomeVisitable : public VisitableInterface
{
public:
SomeVisitable( const T& element ) : element_(element) {}
virtual void accept( Visitor& v ) const
{
...
}
virtual bool isPOD() const
{
return std::is_pod<T>::value;
}
private:
const T element_;
};
int main()
{
std::vector<VisitableInferface*> vec;
PodVisitor podVisitor;
ClassVisitor classVisitor;
for( auto i = vec.begin(); i != vec.end(); ++i )
{
if( (*i)->isPOD() )
(*i)->accept( podVisitor );
else
(*i)->accept( classVisitor );
}
}
I think you've misunderstood the visitor pattern.
Maybe. Actually sometimes I feel the vocabulary seems reversed; i.e. it
feels more intuitive that visit() should be named accept() and vice
versa. In the example below I have named them by the book.
What goes in your accept method?????
This is typically where the double dispatch comes in that does away
with the need for switching.
However this involves a polymorphic interface which doesn't fit well
with templates.
I will try to show a simplified version of what I'm trying to achieve.
The main idea is to create a wrapper to boost::format that will provide
lazy evaluation of the arguments.
class LazyArgumentList
{
public:
template<typename T>
LazyFormat& operator%( const T& t )
{
argumentList_.push_back( new LazyArgument<T>( t ) );
}
private:
std::vector<ArgumentInterface*> argumentList_;
};
template<typename T>
class LazyArgument : public ArgumentInterface
{
public:
LazyArgument( const T& t ) : arg_(arg) {}
virtual void accept( LazyFormat& format )
{
format.visit( arg_ );
}
private:
const T arg_;
};
// This would be the ideal, but is not possible since
// partial specialization is not allowed on function
// templates.
class LazyFormat
{
public:
void applyArguments( const LazyArgumentList& list )
{
auto argEnd = list.getArgs().end();
for( auto i = list.getArgs().begin(); i != end; ++i )
(*i)->accept( *this );
}
template<typename T, bool isPOD = std::is_pod<T>::value>
void visit( const T& t )
{
boostFormat_ % t;
}
template<typename T, false>
void visit( const T& t )
{
std::stringstream s;
s << t;
boostFormat_ % s.str();
}
private:
boost::format boostFormat_;
};
// But it seems that it won't work with std::is_pod so I have
// to do like this.
class LazyFormat
{
public:
void applyArguments( const LazyArgumentList& list )
{
auto argEnd = list.getArgs().end();
for( auto i = list.getArgs().begin(); i != end; ++i )
(*i)->accept( *this );
}
void visit( int t ) { boostFormat_ % t; }
void visit( float t ) { boostFormat_ % t; }
void visit( char t ) { boostFormat_ % t; }
// ... etc for each POD ...
// For all non-POD.
template<typename T>
void visit( const T& t )
{
std::stringstream s;
s << t;
boostFormat_ % s.str();
}
private:
boost::format boostFormat_;
};
Another confusing aspect of your example is:
SomeVisitable<int> sv;
assert(sv.isPOD()); // !!!!!
sv is NOT POD so why do you want to say that it is?
You are completely right. I don't like the sv.isPOD() solution either,
and you certainly provided a flaw here.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]