2006-06-30 Roland Levillain <roland(a)lrde.epita.fr>
* oln/arith/internal/opdecls.hh (oln_arith_declare_binop_procs_):
Re-enable the third operator, but rename it as OPNAME_with_ret.
* oln/morpho/geodesic_erosion.hh: Typos in comments.
Index: 10.224/olena/oln/arith/internal/opdecls.hh
--- 10.224/olena/oln/arith/internal/opdecls.hh Thu, 22 Jun 2006 10:49:20 +0200 levill_r (oln/b/22_opdecls.hh 1.20 600)
+++ 10.224(w)/olena/oln/arith/internal/opdecls.hh Fri, 30 Jun 2006 11:40:04 +0200 levill_r (oln/b/22_opdecls.hh 1.20 600)
@@ -1,4 +1,5 @@
-// Copyright (C) 2001, 2002, 2003, 2004 EPITA Research and Development Laboratory
+// Copyright (C) 2001, 2002, 2003, 2004, 2006 EPITA Research and
+// Development Laboratory
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
@@ -175,9 +176,41 @@
#define default_functor_return_type_cst_(OPNAME, I1, T2) \
typename default_functor_type_cst_(OPNAME, I1, T2)::result_type
-/// Declare front-end functions.
+/** \def Declare front-end functions.
+
+ OPNAME_with_ret used to be named OPNAME previously, but it caused
+ ambiguous calls with modern (and more compliant) compilers
+ (GCC 4.0, GCC 4.1, ICC 9.1). These compilers consider that
+
+ \code
+ OPNAME<T>(ima1, ima2);
+ \endcode
+
+ could be both interpreted as a call to
+
+ \code
+ template<class I1, class I2> inline
+ typename arith_return_type_proxy_##OPNAME##_<I1, I2>::ret
+ OPNAME(const abstract::image<I1>& input1,
+ const abstract::image<I2>& input2)
+
+ (with I1 = T and I2 = typeof(ima2))
+ \endcode
+
+ as well as a call to
+
+ \code
+ template<class IRet, class I1, class I2> inline
+ typename mute<I1, oln_value_type(IRet)>::ret
+ OPNAME(const abstract::image<I1>& input1,
+ const abstract::image<I2>& input2)
+
+ (with IRet = T, I1 = typeof(ima1), I2 = typeof(ima2)).
+ \endcode
+
+ Using different names for these operators removes the ambiguity. */
# define oln_arith_declare_binop_procs_(OPNAME) \
- /* \
+ /* \
FIXME: this is a workaround for an odd bug of icc and como \
http://www.lrde.epita.fr/cgi-bin/twiki/view/Know/MysteriousTemplateFunction… \
Remove this traits and use its content directly when this bug gets fixed. \
@@ -218,41 +251,21 @@
T2, \
ntg_return_type(OPNAME, T1, T2)>()), \
input1, input2); \
+ } \
+ \
+ /* Same as above, with inline conversion in the functor. */ \
+ /* This operator has a `_with_ret' suffix for disambiguation purpose */ \
+ /* (see above). */ \
+ template<class IRet, class I1, class I2> inline \
+ typename mute<I1, oln_value_type(IRet)>::ret \
+ OPNAME##_with_ret(const abstract::image<I1>& input1, const abstract::image<I2>& input2) \
+ { \
+ return apply2(f_##OPNAME<oln_value_type(I1), \
+ oln_value_type(I2), \
+ oln_value_type(IRet)>(), \
+ input1, input2); \
}
-/* FIXME: Used to be part from the previous macro, but causes ambiguous
- calls with G++ 4.0 and 4.1: theses compiler seems to consider that
-
- OPNAME(ima1, ima2);
-
- could be both interpreted as a call to
- template<class I1, class I2> inline
- typename arith_return_type_proxy_##OPNAME##_<I1, I2>::ret
- OPNAME(const abstract::image<I1>& input1,
- const abstract::image<I2>& input2)
-
- or
-
- template<class IRet, class I1, class I2> inline
- typename mute<I1, oln_value_type(IRet)>::ret
- OPNAME(const abstract::image<I1>& input1,
- const abstract::image<I2>& input2)
-
- despite the fact that this call doesn't resolve the first parameter
- (`IRet') of the second version. It might be a bug in the 4.x branch
- of G++. */
-//
-//
-// /* Same as above, with inline conversion in the functor. */
-// template<class IRet, class I1, class I2> inline
-// typename mute<I1, oln_value_type(IRet)>::ret
-// OPNAME(const abstract::image<I1>& input1, const abstract::image<I2>& input2)
-// {
-// return apply2(f_##OPNAME<oln_value_type(I1),
-// oln_value_type(I2),
-// oln_value_type(IRet)>(),
-// input1, input2);
-// }
/// Apply OPNAME with a constant as second operand.
# define oln_arith_declare_binopcst_procs_(OPNAME) \
Index: 10.224/olena/oln/morpho/geodesic_erosion.hh
--- 10.224/olena/oln/morpho/geodesic_erosion.hh Wed, 14 Apr 2004 00:08:50 +0200 thivol_d (oln/36_geodesic_e 1.20 600)
+++ 10.224(w)/olena/oln/morpho/geodesic_erosion.hh Fri, 23 Jun 2006 18:45:56 +0200 levill_r (oln/36_geodesic_e 1.20 600)
@@ -47,7 +47,7 @@
** \param N Exact type of neighborhood.
**
** \arg marker Image to work on.
- ** \arg mask Image used for geodesic dilation.
+ ** \arg mask Image used for geodesic erosion.
** \arg Ng Neighborhood to use.
**
** Compute the geodesic erosion of marker with respect to the
@@ -104,13 +104,13 @@
** \param N Exact type of neighborhood.
**
** \arg marker Image to work on.
- ** \arg mask Image used for geodesic dilation.
+ ** \arg mask Image used for geodesic erosion.
** \arg Ng Neighborhood to use.
**
- ** Compute the geodesic erosion of marker with respect to the
- ** mask mask image using se as structural element. Soille
+ ** Compute the geodesic erosion of marker with respect to the
+ ** mask image using se as structural element. Soille
** p.156. Computation is performed by hand (i.e without calling
- ** dilation).
+ ** erosion).
**
** \pre Marker must be greater or equal than mask.
**
Sorry for the ugly patch, but Vcs is broken on my machine, and prdiff
neither works.
Index: 10.222/olena/ChangeLog
Index: 10.222/olena/oln/arith/internal/opdecls.hh
--- 10.222/olena/ChangeLog Thu, 15 Sep 2005 17:50:38 +0200 levill_r (oln/o/30_ChangeLog 1.27.1.36.1.3.1.11.1.5.1.64.1.47.1.93.1.27.2.4 600)
+++ 10.222(w)/olena/ChangeLog Wed, 21 Jun 2006 19:30:10 +0200 levill_r (oln/o/30_ChangeLog 1.27.1.36.1.3.1.11.1.5.1.64.1.47.1.93.1.27.2.4 600)
@@ -1,3 +1,8 @@
+2006-06-21 Roland Levillain <roland(a)lrde.epita.fr>
+
+ * oln/arith/internal/opdecls.hh (oln_arith_declare_binop_procs_):
+ Remove the third operator, causing a an ambiguity with G++ 4.0.
+
2005-09-15 Roland Levillain <roland(a)lrde.epita.fr>
Adjust for G++ 4.0.
--- 10.222/olena/oln/arith/internal/opdecls.hh Tue, 13 Apr 2004 17:31:32 +0200 van-vl_n (oln/b/22_opdecls.hh 1.19 600)
+++ 10.222(w)/olena/oln/arith/internal/opdecls.hh Fri, 16 Jun 2006 17:50:32 +0200 levill_r (oln/b/22_opdecls.hh 1.19 600)
@@ -218,18 +218,41 @@
T2, \
ntg_return_type(OPNAME, T1, T2)>()), \
input1, input2); \
- } \
- \
- /* Same as above, with inline conversion in the functor. */ \
- template<class IRet, class I1, class I2> inline \
- typename mute<I1, oln_value_type(IRet)>::ret \
- OPNAME(const abstract::image<I1>& input1, const abstract::image<I2>& input2) \
- { \
- return apply2(f_##OPNAME<oln_value_type(I1), \
- oln_value_type(I2), \
- oln_value_type(IRet)>(), \
- input1, input2); \
}
+/* FIXME: Used to be part from the previous macro, but causes ambiguous
+ calls with G++ 4.0 and 4.1: theses compiler seems to consider that
+
+ OPNAME(ima1, ima2);
+
+ could be both interpreted as a call to
+
+ template<class I1, class I2> inline
+ typename arith_return_type_proxy_##OPNAME##_<I1, I2>::ret
+ OPNAME(const abstract::image<I1>& input1,
+ const abstract::image<I2>& input2)
+
+ or
+
+ template<class IRet, class I1, class I2> inline
+ typename mute<I1, oln_value_type(IRet)>::ret
+ OPNAME(const abstract::image<I1>& input1,
+ const abstract::image<I2>& input2)
+
+ despite the fact that this call doesn't resolve the first parameter
+ (`IRet') of the second version. It might be a bug in the 4.x branch
+ of G++. */
+//
+//
+// /* Same as above, with inline conversion in the functor. */
+// template<class IRet, class I1, class I2> inline
+// typename mute<I1, oln_value_type(IRet)>::ret
+// OPNAME(const abstract::image<I1>& input1, const abstract::image<I2>& input2)
+// {
+// return apply2(f_##OPNAME<oln_value_type(I1),
+// oln_value_type(I2),
+// oln_value_type(IRet)>(),
+// input1, input2);
+// }
/// Apply OPNAME with a constant as second operand.
# define oln_arith_declare_binopcst_procs_(OPNAME) \
https://svn.lrde.epita.fr/svn/oln/trunk/static
ChangeLog | 13 +++++
tests/tour.cc | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 133 insertions(+), 6 deletions(-)
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Document method checks in Static tour.
* tests/tour.cc (static_hierarchy_with_methods::test): Rename
as...
(static_hierarchy_with_methods::test1): ...this.
(main): Adjust.
(static_hierarchy_with_methods::D): New.
(static_hierarchy_with_methods::test2): New.
(static_hierarchy_with_method_checks): New section.
Add a reference (Concept Checking).
2006-06-15 Roland Levillain <roland(a)lrde.epita.fr>
Index: tests/tour.cc
--- tests/tour.cc (révision 503)
+++ tests/tour.cc (révision 504)
@@ -31,6 +31,7 @@
#include <cassert>
#include <mlc/assert.hh>
+#include <mlc/contract.hh>
#include <mlc/is_a.hh>
#include <mlc/cmp.hh>
@@ -394,7 +395,7 @@
namespace static_hierarchy_with_methods
{
- void test()
+ void test1()
{
C c;
assert (c.foo() == 4);
@@ -412,20 +413,133 @@
} // end of namespace static_hierarchy_with_methods
-// FIXME: Introduce static checks of methods (kind of concept checking).
+// --------------------------- //
+// Enforcing method checking. //
+// --------------------------- //
+
+/* For a given `Exact' type, consider the `A<Exact>::foo' method.
+ This method relies on the fact that `Exact' has an `impl_foo'
+ method. However, the compiler let you instantiate an a class
+ `A<Exact>' with an `Exact' type not fulfilling this requirement,
+ and even worse, you can instantiate an object of this ill-formed
+ type! The compiler will complain only when it tries to resolve the
+ call to the (missing) `impl_foo' method. */
+
+namespace static_hierarchy_with_methods
+{
+
+ // For instance, let's introduce an ill-formed concrete subclass of A.
+ struct D : public A<D>
+ {
+ // No `impl_foo'.
+ };
+
+ /* `D' is not a valid exact type for A. Despite this fact, we can
+ instantiate this template with `D', as well as an object of this
+ type! */
+ void test2()
+ {
+ // Valid (!).
+ typedef A<D> A_D;
+ // Equally valid (!).
+ A_D a;
+ // This call would fail if it were not disabled.
+#if 0
+ a.foo();
+#endif
+ }
+
+} // end of namespace static_hierarchy_with_methods
+
+
+/* Metalic proposes a concept checking tool similar to the one used in
+ the Boost Concept Check Library (BCCL) [2],
+ `mlc_check_method_impl'. We use it to check that SCOOP abstract
+ polymorphic methods defined in an abstract class have a valid
+ implementation in one of the subclasses (i.e., "between" this
+ abstraction and the exact type). */
+
+namespace static_hierarchy_with_method_checks
+{
+
+ template <typename Exact>
+ struct A : public stc::any<Exact>
+ {
+ int foo() { return this->exact().impl_foo(); }
+ int impl_foo() { return 1; }
+ int bar() { return this->exact().impl_bar(); }
+
+ /* Method checks are placed in the destructor, since they must
+ reside within a function body. */
+ ~A()
+ {
+ /* `foo' is abstract in `A'. Ensure A's subclasses define an
+ implementation for this method. */
+ mlc_check_method_impl(Exact, int, bar, /* no arg */, /* no const */);
+ }
+ };
+
+ template <typename Exact>
+ struct B : public A< stc_find_exact(B, Exact) >
+ {
+ int impl_foo() { return 2; }
+ int impl_bar() { return 3; }
+ };
+
+ struct C : public B<C>
+ {
+ int impl_foo() { return 4; }
+ };
+
+ struct D : public A<D>
+ {
+ // No `impl_foo'.
+ };
+
+
+ void test()
+ {
+ /* Invalid template instantiation, because of `impl_foo' missing.
+ Upon this code, the compiler would emit an error message
+ similar to this one:
+
+ error: 'impl_bar' is not a member of
+ 'static_hierarchy_with_method_checks::D'
+
+ */
+#if 0
+ typedef A<D> A_D;
+ A_D a;
+#endif
+ }
+
+} // end of namespace static_hierarchy_with_method_checks
+
+/*-------.
+| Misc. |
+`-------*/
+
// Run dynamic tests.
int main()
{
static_hierarchy_with_any::test();
- static_hierarchy_with_methods::test();
+ static_hierarchy_with_methods::test1();
}
-/* References:
- [1] Coplien, James O. (1995, February). "Curiously Recurring
- Template Patterns". C++ Report: 24-27. */
+
+/*-------------.
+| References. |
+`-------------*/
+
+/* [1] James O. Coplien. ``Curiously Recurring Template
+ Patterns''. C++ Report: 24-27. 1995, February.
+
+ [2] Jeremy Siek, Andrew Lumsdaine. ``Concept Checking: Binding
+ Parametric Polymorphism in C++''. In Proceedings of the ``Workshop
+ on C++ Template Programming''. 2000. */
https://svn.lrde.epita.fr/svn/oln/trunk/static
ChangeLog | 18 +++++++++++++++++
tests/tour.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 66 insertions(+), 13 deletions(-)
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
More on SCOOP methods in Static tour.
* tests/tour.cc (dynamic_hierarchy::A::foo)
(dynamic_hierarchy::A::bar, dynamic_hierarchy::B::foo)
(dynamic_hierarchy::B::bar, dynamic_hierarchy::C::foo): Return an
int value.
(static_hierarchy_with_methods::A::foo)
(static_hierarchy_with_methods::A::impl_foo)
(static_hierarchy_with_methods::A::bar)
(static_hierarchy_with_methods::B::impl_foo)
(static_hierarchy_with_methods::B::impl_bar)
(static_hierarchy_with_methods::C::impl_foo): Likewise.
(static_hierarchy_with_methods): Add comments.
(static_hierarchy_with_methods::test): New.
(main): Call it.
Index: tests/tour.cc
--- tests/tour.cc (révision 502)
+++ tests/tour.cc (copie de travail)
@@ -75,25 +75,25 @@
struct A
{
// A virtual method.
- virtual void foo() { /* ... */ }
+ virtual int foo() { return 1; }
// A virtual pure method.
- virtual void bar() = 0;
+ virtual int bar() = 0;
};
// `B' is a concrete class.
struct B
{
// A redefined method.
- virtual void foo() { /* ... */ }
+ virtual int foo() { return 2; }
// `B::bar' is defined.
- virtual void bar() { /* ... */ }
+ virtual int bar() { return 3; }
};
// `C' is a concrete class.
struct C
{
// `B::foo' is redefined.
- virtual void foo() { /* ... */ }
+ virtual int foo() { return 4; }
};
} // end of namespace dynamic_hierarchy
@@ -338,9 +338,22 @@
// Methods. //
// --------- //
-// Add the methods.
+/* We have laid down the foundations of our classes. Now it's time to
+ add some methods.
-// FIXME: Comments.
+ Unlike classic C++, SCOOP doesn't use the `virtual' keyword to
+ define polymorphic methods. As SCOOP performs a static resolution
+ of method calls, it can't rely on `virtual' (which is dynamic per
+ se). Instead, a manual dispatch of method call is used: each
+ polymorphic method is turned into a facade, and there is one
+ implementation per class defining this method actually. The facade
+ retrieves the exact type of the object, and calls the
+ implementation corresponding to this type. A SCOOP abstract
+ polymorphic method (the equivalent of C++ ``virtual pure'' method)
+ has no implementation in the class where its facade is defined.
+
+ The convention is to name `impl_m' the implementation(s) of the
+ facade `m'. */
namespace static_hierarchy_with_methods
{
@@ -351,12 +364,12 @@
/* Facade of a statically-dispatched method. Notice there is no
`virtual' keyword: the (static) dispatch is done manually
through the delegation to impl_foo. */
- void foo() { this->exact().impl_foo(); }
+ int foo() { return this->exact().impl_foo(); }
// Implementation of the method.
- void impl_foo() { /* ... */ }
+ int impl_foo() { return 1; }
// A ``virtual'' pure (i.e., abstract) method.
- void bar() { this->exact().impl_bar(); }
+ int bar() { return this->exact().impl_bar(); }
// (No `impl_bar', since bar is abstract.)
};
@@ -364,20 +377,41 @@
struct B : public A< stc_find_exact(B, Exact) >
{
// A redefined method.
- void impl_foo() { /* ... */ }
+ int impl_foo() { return 2; }
// B::bar (implementation) is defined.
- void impl_bar() { /* ... */ }
+ int impl_bar() { return 3; }
};
struct C : public B<C>
{
// Redefinition.
- void impl_foo() { /* ... */ }
+ int impl_foo() { return 4; }
};
} // end of namespace static_hierarchy_with_methods
+namespace static_hierarchy_with_methods
+{
+
+ void test()
+ {
+ C c;
+ assert (c.foo() == 4);
+ assert (c.bar() == 3);
+
+ B<C>& b = c;
+ assert (b.foo() == 4);
+ assert (b.bar() == 3);
+
+ A<C>& a = c;
+ assert (a.foo() == 4);
+ assert (a.bar() == 3);
+ }
+
+} // end of namespace static_hierarchy_with_methods
+
+
// FIXME: Introduce static checks of methods (kind of concept checking).
@@ -385,6 +419,7 @@
int main()
{
static_hierarchy_with_any::test();
+ static_hierarchy_with_methods::test();
}
/* References:
https://svn.lrde.epita.fr/svn/oln/trunk/static
ChangeLog | 15 +++++++++++-
tests/tour.cc | 70 ++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 73 insertions(+), 12 deletions(-)
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
More on the retrieval of and the conversion to the exact type in
Static tour.
* tests/tour.cc (static_hierarchy_with_any): More on the retrieval
of and the conversion to the exact type.
(main): Run dynamic tests.
(static_hierarchy_with_any::A)
(static_hierarchy_with_a_non_leaf_concrete_class::A)
(static_hierarchy_with_methods::A): Use stc::any instead of
stc::any__simple.
2006-06-14 Roland Levillain <roland(a)lrde.epita.fr>
Add stc_to_exact and stc_to_exact_ macros.
Index: tests/tour.cc
--- tests/tour.cc (révision 500)
+++ tests/tour.cc (copie de travail)
@@ -28,7 +28,14 @@
/// \file tests/tour.cc
/// \brief A tour of Static and SCOOP features.
+#include <cassert>
+
+#include <mlc/assert.hh>
+#include <mlc/is_a.hh>
+#include <mlc/cmp.hh>
+
# include <stc/any.hh>
+#include <stc/exact.hh>
# include <stc/find_exact.hh>
// FIXME: ``Fil rouge'': building a small (but complete) static
@@ -41,7 +48,7 @@
// having introduced the vtypes.
// FIXME: Things to show:
-// - exact
+// - exact (more)
// - super
// - virtual types (and macros for super)
// - multiple super
@@ -167,8 +174,8 @@
to this type. In fact, there is not a single `stc::any' class,
but several, which have their advantages and drawbacks
w.r.t. speed, memory print and support for diamond inheritance.
- We'll only deal with `stc::any__simple' in this Static tour:
- where you'll see `stc::any', simply read `stc::any__simple'.
+ We'll only deal with `stc::any' (an alias for `stc::any__simple')
+ in this Static tour.
`stc::any' is used as the base class of any top class of a static
hierarchy. It is passed the `Exact' type, just like any non-leaf
@@ -176,7 +183,7 @@
derived, i.e., at the bottom of an inheritance tree). */
template <typename Exact>
- struct A : public stc::any__simple<Exact>
+ struct A : public stc::any<Exact>
{
};
@@ -199,11 +206,47 @@
} // end of namespace static_hierarchy_with_any
-// ------------ //
-// stc::exact. //
-// ------------ //
+// -------------------------------- //
+// Getting back to the exact type. //
+// -------------------------------- //
-// FIXME: To do.
+namespace static_hierarchy_with_any
+{
+ void test()
+ {
+ // Metalic assertions.
+ mlc::assert_< mlc_is_a_(C, A) >::check();
+ mlc::assert_< mlc_is_a_(C, B) >::check();
+
+
+ // Getting the exact type.
+
+ // `stc::any' has an `exact_type' typedef.
+ typedef A<C>::exact_type exact_type_of_A_1;
+ // But you can also use stc_to_exact_ to get this type.
+ typedef stc_to_exact_(A<C>) exact_type_of_A_2;
+ // Check these types.
+ mlc::assert_< mlc_eq(exact_type_of_A_1, C) >::check();
+ mlc::assert_< mlc_eq(exact_type_of_A_2, C) >::check();
+
+
+ // Converting an object to its exact type.
+
+ // Create a C.
+ C c;
+ // See it through an abstraction.
+ A<C>& a = c;
+ // And get it back, with no runtime overhead (i.e., dynamic_cast).
+ C& c2 = a.exact();
+ // Ensure we got back the same object.
+ assert (&c2 == &c);
+
+ // stc::exact provides the same service.
+ C& c3 = stc::exact(a);
+ assert (&c3 == &c);
+ }
+
+} // end of namespace static_hierarchy_with_any
// --------------------------- //
@@ -236,7 +279,7 @@
/* A is left unchanged (it is still an abstract class). */
template <typename Exact>
- struct A : public stc::any__simple<Exact>
+ struct A : public stc::any<Exact>
{
};
@@ -303,7 +346,7 @@
{
template <typename Exact>
- struct A : public stc::any__simple<Exact>
+ struct A : public stc::any<Exact>
{
/* Facade of a statically-dispatched method. Notice there is no
`virtual' keyword: the (static) dispatch is done manually
@@ -337,7 +380,12 @@
// FIXME: Introduce static checks of methods (kind of concept checking).
-int main() {}
+
+// Run dynamic tests.
+int main()
+{
+ static_hierarchy_with_any::test();
+}
/* References: