Thread overview | ||||||
---|---|---|---|---|---|---|
|
September 09, 2004 [bug report] recursive template definition | ||||
---|---|---|---|---|
| ||||
The dmc compiler crashes on recursive template definitions without any stop condition, without issuing any error message. Example: template<int N> float power(float x) { return power<N-1>(x)*x; } int main() { power<10>(2); } In most cases this isn't a problem, because such source code is incorrect anyway, but it also crashes with the following function used to quickly compute small integer powers (which works well when compiled with Borland C++): template<unsigned N, typename T> inline T power(T x) { return N == 0 ? 1 : (N == 1 ? x : (N == 2 ? x*x : (N == 3 ? x*x*x : (N == 4 ? power<2>(power<2>(x)) : (N == 9 ? power<3>(power<3>(x)) : (N == 12 ? power<3>(power<4>(x)) : (N == 16 ? power<4>(power<4>(x)) : (N == 25 ? power<5>(power<5>(x)) : (N%2 == 0 ? power<2>(power<N/2>(x)) : (N%3 == 0 ? power<3>(power<N/3>(x)) : power<N-1>(x)*x )))))))))); } It doesn't crash when the same function is written this way (but I couldn't figure out how to templatise the type of the function argument when using this solution): template<unsigned N> inline float power(float x) { return N%2 == 0 ? power<2>(power<N/2>(x)) : (N%3 == 0 ? power<3>(power<N/3>(x)) : x*power<N-1>(x)); } template<> inline float power<25>(float x) { return power<5>(power<5>(x)); } template<> inline float power<16>(float x) { return power<4>(power<4>(x)); } template<> inline float power<12>(float x) { return power<3>(power<4>(x)); } template<> inline float power<9>(float x) { return power<3>(power<3>(x)); } template<> inline float power<4>(float x) { return power<2>(power<2>(x)); } template<> inline float power<3>(float x) { return x*x*x; } template<> inline float power<2>(float x) { return x*x; } template<> inline float power<1>(float x) { return x; } template<> inline float power<0>(float x) { return 1; } |
September 09, 2004 Re: [bug report] recursive template definition | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szabolcs Horvát | Szabolcs Horvát wrote: > In most cases this isn't a problem, because such source code is incorrect > anyway, but it also crashes with the following function used to quickly > compute small integer powers (which works well when compiled with Borland > C++): > > template<unsigned N, typename T> > inline T power(T x) { > return > N == 0 > ? 1 > : (N == 1 > ? x > : (N == 2 > ? x*x > : (N == 3 > ? x*x*x > : (N == 4 > ? power<2>(power<2>(x)) > : (N == 9 > ? power<3>(power<3>(x)) > : (N == 12 > ? power<3>(power<4>(x)) > : (N == 16 > ? power<4>(power<4>(x)) > : (N == 25 > ? power<5>(power<5>(x)) > : (N%2 == 0 > ? power<2>(power<N/2>(x)) > : (N%3 == 0 > ? power<3>(power<N/3>(x)) > : power<N-1>(x)*x > )))))))))); > } Sorry, I don't think you're allowed to do that. The compiler can't be expected to know which functions to instantiate. > It doesn't crash when the same function is written this way (but I couldn't > figure out how to templatise the type of the function argument when using > this solution): By coincidence, I was playing around with doing something like this the other day. One way to do this kind of thing is by using an extra paramter to select the required function. I wrote this: namespace detail { enum power_type { zero, one, even, odd }; template <power_type N> struct gen_power_type {}; template <unsigned n, typename T> inline T power(T const& x, gen_power_type<zero> const&) { return 1; } template <unsigned n, typename T> inline T power(T const& x, gen_power_type<one> const&) { return x; } template <unsigned n, typename T> inline T power(T const& x, gen_power_type<even> const&) { return power<n/2>(x*x); } template <unsigned n, typename T> inline T power(T const& x, gen_power_type<odd> const&) { return x * power<n-1>(x); } template <unsigned n, typename T> inline T power(T const& x) { return detail::power<n>(x, detail::gen_power_type< (n == 0 ? detail::zero : n == 1 ? detail::one : n % 2 == 0 ? detail::even : detail::odd)>()); } } template <unsigned n, typename T> T power(T const& x) { return detail::power<n>(x); I used an enum there, but you could you this technique with integers instead. An alternative is to use a specialised template structure: namespace detail { template <unsigned n> struct power_impl; template <> struct power_impl<0> { template <class T> static inline T calc(T const& x) { return 1; } }; template <> struct power_impl<1> { template <class T> static inline T calc(T const& x) { return x; } }; template <unsigned n> struct power_impl { template <class T> static inline T calc(T const& x) { if(n & 1 == 0) return power_impl<(n >> 1)>::calc(x * x); else return x * power_impl<n-1>::calc(x); } }; } template <unsigned n, typename T> T power(T const& x) { return detail::power_impl<n>::calc(x); } I hope that helps. Daniel |
September 13, 2004 Re: [bug report] recursive template definition | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel James | Daniel James wrote:
> An alternative is to use a specialised template structure:
>
> I hope that helps.
>
> Daniel
Thank you, it did help.
But when I tried to use the same technique inside a class, the compiler
failed to instantiate the member classes.
This is a minimal code fragment that produces the error:
class Class {
template<unsigned U> struct Member { static void g() {} };
public:
void f() { Member<0>::g(); }
};
int main() {
Class u;
u.f();
}
Borland C++ 5.5 compiles this without any error while dmc 8.40 stops with
test.cpp(5) : Error: '?$Member@Class@$0@' is not a member of struct 'Class'
--- errorlevel 1
Do you think this is a compiler bug or am I doing something wrong again?
Szabolcs
|
September 16, 2004 Re: [bug report] recursive template definition | ||||
---|---|---|---|---|
| ||||
Posted in reply to Szabolcs Horvát | Szabolcs Horvát wrote:
> class Class {
> template<unsigned U> struct Member { static void g() {} };
> public:
> void f() { Member<0>::g(); }
> };
>
> int main() {
> Class u;
> u.f();
> }
>
>
> Borland C++ 5.5 compiles this without any error while dmc 8.40 stops with
>
> test.cpp(5) : Error: '?$Member@Class@$0@' is not a member of struct 'Class'
> --- errorlevel 1
>
> Do you think this is a compiler bug or am I doing something wrong again?
Yep, it's a bug. To work around it you can use a typedef:
void f() {
typedef Member<0> Member_0;
Member_0::g();
}
I've come across similar problems when using static member variables.
Daniel
|
Copyright © 1999-2021 by the D Language Foundation