
"Tobias Schwinger" <tschwinger@neoscientists.org> wrote in message news:elu6fo$ib2$1@sea.gmane.org...
Gennadiy Rozental wrote:
Here is my logic:
we should prefer to minimize dependency,
Where are we doing that? A template written towards concepts has no dependencies while a separate-translation-unit-solution depends at least on vector, variant
In part yes. But usually primary source of dependencies is not an interface, but implementation. So in this regard usually it's more preferrable to hide implementation to coding in generic concepts. Also STL components are not so much an extra dependancy anyway (they are present in many/most non-trivial translation units anyway)
and whatever types that variant is specialized with.
tuple will depend on the same types as well.
unless performance in visibly hurt in performance critical area => we should prefer to place implementation in cpp files under the same circomstances => we were talking anout output operation, so performace is a) not that critical b) mostly lost in syste i/o
=> i/o operation we should prefer to implement offline
In other words: for the problem at hand inline implementation is disadvantage.
The bad extensibility of your proposed solution is much worse (especially for IO):
I don't argue that tuple based solution is much more easily extandible.
Extending the variant requires you to touch the header (and can cause a major rebuild). It also requires you to add a switch case for the new type to the code in the cpp file. If you have a lot of "ostreamable" types (which is not too uncommon of a case), you end up with many (totally unecessary) dependencies that will cause your cpp file to be rebuilt a lot.
In practive unless you are writing a generic component to be used by wide audience, set of used types may not change that frequently In case if I do have a lof of different types or this set is not fixed, I would prefer header based solution either
2. It allows dynamically sized entries, so you could skip some of the default values 3. It's as fast of could be even faster since we don't need to pass big structures around
AFAIK Boost.Variant calculates the storage size based on the largest object (just like a union does). It also has good reason to do so since heap allocation is an expensive operation. IOW if we have vector< variant<some_huge_class,int,int> > and most of the variants in the vector are ints we're wasting memory.
In case like this we should be using snart_ptr<some_huge_class> instead of some_huge_class as a member of tuple. But for the task at hand I don't see this as a real problem anyway.
Well, the statements from your OP read pretty general to me (and, excuse my bluntness, these two in particular are just plainly wrong in any context).
How are they wrong? 2. ... Let's say you have record with 10 optional elements. tuple based solution will end up compiling in anything from 1 to 10! different versions of the same function, while offline version will be only one. Also in case if you always want output in the same 10 column format I dont see easy way to implement it using tuples. 3. ... If you take tuples by value you will end up copying huge structures. If not - the only difference I could see in an extra jump command per value, in practice completely negligeble. Also keep in mind that tupble based solution will create tuples in place while variant collections could be used throughout the application as a generic record storage.
Again. It's probably applicable for the performance critical area. For the output operation I would stick with BOOST_FOREACH or stl algorithm.
In my experience performance critical tasks are comparatively rare and we should not blur the clarity and simplicity for no particular reason.
Yes, we shouldn't blur the clarity. The Fusion solution is simpler and cleaner (just implement both ways and you'll see).
Unfortunately I am not well versed in tuple/fusion interfaces. Lets say you have comparatively expensive overloaded output operation foo. BOOST_FOREACH solutions would look something like this (ignoring header line) printer p( foo ) // don't remember exact syntax for the visitor definition BOOST_FOREACH( my_v const& v, record ) { apply_visitor( p, v ); } After compiler optimizations it should be equivalent to BOOST_FOREACH( my_v const& v, record ) { switch( v.type){ case 0: foo( *(type0*)v.data ); ... case 10: foo( *(type10*)v.data ); } } So that' why I think variant solution should be as fact (almost). If you avoid the looping it will be even closer. Gennadiy