|
Boost : |
From: Tobias Schwinger (tschwinger_at_[hidden])
Date: 2006-11-27 18:14:11
Daryle Walker wrote:
>>Did you consider using expression templates to
>>
>>- eliminate temporaries in expressions
>>- detect temporaries to use in-place operations instead of copying ones, IOW
>>exploiting destructibility of values
>>- decorate the allocator for stack-based allocation during evaluation
>>- replacing widening conversion operations with views
>>
>>?
>
>
> No. An type aided with expression templates eventually has to forward to
> some algorithms somewhere. I substituted for that by having member
> functions that combine operations together. Only operations that can be
> reasonably combined are done; operations that can interfere with each other
> aren't combined. That's why division and modulus don't combine with
> anything besides each other. However, a class like mine can be used as the
> implementation class for something that does use expression templates!
> Also, expression templates would interfere with presenting the code clearly
> (for educational purposes).
I see.
>
>>The last point of the above list can probably be implemented with a "hollow
>>base", CRTP and deduce-from-base instead of ET (similar to polymorphism of
>>parsers in Spirit).
>
>
> What's CRTP stand for?
>
It's the Curiously Recurring Template Pattern (some code attached).
You can make a base class know its dervied class by specializing a base class template with the derived type. This way you can use static_cast to downcast the 'this' pointer and implement compile time polymorphism. I gave a code example in reply to Maarten Kronenburg.
>
>>The ET approach could also be used to implement interesting syntactic
>>properties. I once wrote a Wiki page about it:
>>
>> http://tinyurl.com/qtyhh
>
>
> I've read that page. I got some of my ideas from it (like the memory
> management at the end).
>
> Natural logarithm and/or any base?
log_Radix is there already and it's called digit_count(), isn't it?
Base N where N is an integer would be useful (e.g. to deal with tree structures larger than main memory).
> How can it be done, especially since I
> would be limited to integer arithmetic and results? I only have access to
> Knuth's _The Art of Computer Programming_ books, Wikipeida, plus occasional
> bignum pages I see on the web. I don't have access to the ACM/IEEE stuff,
> where I suspect a lot of "kewl" algorithms live.
Well, I don't have a really cool algorithm in my pocket. What follows is possibly amateurish intuitive guessing - there are probably better algorithms around (probably even in Knuth's TAOCP). Anyway, I'll give it a try:
Let's first look at cases where things are easy:
Given Radix = pow(b_r,n), where b_r,n are integers
log_b_r(x) = log_Radix(x)*n + log_b_r(most_significant_digit(x))
Example:
Radix = 256
b_r = 2, n = 8
log_2(550) = 1*8 + 1 = 9
For some Radix/base combination things can be put to work real smoothly.
BTW. it seems possible to calculate b_r and n at compile time.
Another good thing to check is probably b > x in this case we can just return 0.
For other cases (and for the single digit, above) we pick a rather lame algorithm:
int log(int b, int x)
{
int r = 0; for (int y = 1; y < x; y *= b, ++r);
return r;
}
Now the question is: "Can we estimate a value less than the result so we can let (r,y) start at (r_0,pow(b,r_0))?"
It might work to use the least base logarithm we have a special case for (called log_b_r, above - that would be log_Radix, worst case) to do the estimation. Basically the log_a(x) = log_b(x) / log_b(a) sort of thing, while we have to make sure we never over-estimate the result.
<snip>
[ ... Spirit code ... ]
>>But it might be faster to just hand-code the whole thing (in particular to
>>avoid copying), I figure.
>
>
> One key point of my type is that it specifies the radix at compile-time, to
> take full advantage of that, I/O is always done in that radix. This code
> here seems to be fixed at radix-8/10/16, probably using the appropriate I/O
> flags.
It's just a number parser (it matches strings such as "42", "0xcafe" or "077"). It should work with any radix for the destination, but there will be a conversion, of course. Since you mentioned Serialization, I figured that the only IO left would be initialization from human readable form...
Regards,
Tobias
template<typename Derived>
struct base
{
void caller
{
static_cast<Derived*>(this)->compile_time_polymorphic();
}
void compile_time_polymorphic()
{
// default implementation
}
}
struct derived : base<derived>
{
void compile_time_polymorphic()
{
// override
}
}
#include <iostream>
template<class Derived>
struct crtp_base
{
Derived & derived()
{ return *static_cast<Derived*>(this); }
Derived const & derived() const
{ return *static_cast<Derived const *>(this); }
};
class concrete_class
: public crtp_base<concrete_class>
{
int val_state;
public:
concrete_class(int v)
: val_state(v)
{ }
int get_state() const
{ return val_state; }
};
template<class Derived>
void func(crtp_base<Derived> const & arg)
{
std::cout << "value == " << arg.derived().get_state() << std::endl;
}
int main()
{
func( concrete_class(42) );
return 0;
};
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk