Skip to topic | Skip to bottom
Home
Projects
Projects.MetaGeneHorrorShowr1.4 - 27 Nov 2003 - 12:50 - Main.akimtopic end

Start of topic | Skip to actions
While prototyping the Metagene transformations, we encountered several difficulties with the some C++ specific (and often weird) issues. This page is the Hall of shame of the C++ horrors we met.

Nested res

The problem

in ocaml, the expression

let f a b = a + b in f 50 1
is equivalent to
let f = function a -> function b -> a + b in f 50 1
Therefore, we want to translate such expressions with the following construct:
template<unsigned a>
struct f
{
  template<unsigned b>
  struct res
  { 
    enum {res = a + b};
  };
};
The bad news is that this code doesn't compile. Comeau gives the following error: 'declaration of a member with the same name as its class'.

A solution

Here is an equivalent c++ code that compiles.

template<unsigned a>
struct f
{
  struct __ {
    template<unsigned b>
    struct res
    { 
      struct __ {
        enum {res = a + b};
      };
    };
  };
};
The use of this solution means that for a n-ary funcion, we are going to generate 2 * n nested structs. Moreover using this construction makes function application two times heavier.

This can be made simplier with the use of macros:

#define mtg_open           {struct __{
#define mtg_close          };};
#define mtg_apply(F, P)    F< P >::__::res

Our code becomes:

template<unsigned a>
struct f
mtg_open
    template<unsigned b>
    struct res
    mtg_open
        enum {res = a + b};
    mtg_close
mtg_close
This function can be applied the following way:
enum {res = mtg_apply(mtg_apply(plus, 50), 1)};

Our current translation process use implicit boxes (see History: generation paradigm). This asserts us that we will not have two nested structs which the same name.

Use of the typename keyword

Just a flavor of the typename keyword problems

# define mtg_open(T, N, Sn)   template<T N> struct Sn { struct __ {

struct let {
  mtg_open(typename, a, plus)
    mtg_open(typename, b, res)
      typedef [1] mtg_apply(mtg_apply(mtg::plus, a), b)   res;
    mtg_close
  mtg_close
  mtg_open(typename, a, dbl)
      typedef [2] mtg_apply(mtg_apply(mtg::times, mtg::Int <2>), a) res;
  mtg_close
  typedef [3] mtg_apply(mtg_apply(plus, mtg_apply(dbl, mtg::Int <5>)),
                        mtg_apply(mtg_apply(plus, 
                                            mtg_apply(dbl, mtg::Int <10>)), 
                                  mtg::Int <26>))   
       res;
};
Do we need to put the 'typename' keyword in the places [1], [2] and [3]?

Here are some c++ compilers results:

  • E stands for empty
  • T stands for 'typename'
  • x stands for don't care (can be empty or 'typename')

g++ 3.2

[1] [2] [3] compiler result
E E E doesn't compile (hard-to-understand message)
T E E a bit better but doesn't compile
E T E works (with a warning saying that there should be a typename in [1])
T T E g++ segv bouh frown
x x T "error: using `typename' outside of template"

como

[1] [2] [3] compiler result
x x E works without warning smile
x x T "warning: typename may only be used within a template"

That's better, but it should be great that the generated code compiles with g++. In order to make the problem easier we decided that each basic operation (application of one argument, declaration of an int...) would correspond to one 'typedef'. Here is an example:

let res = plus (times 2 4) (times 5 1)

is translated as

typedef plus                            temp7;
typedef times                           temp11;
typedef mtg::Int <2>                    temp12;
typedef temp11::value< temp12 >::res    temp9;
typedef mtg::Int <4>                    temp10;
typedef temp9::value< temp10 >::res     temp8;
typedef temp7::value< temp8 >::res      temp1;
typedef times                           temp5;
typedef mtg::Int <5>                    temp6;
typedef temp5::value< temp6 >::res      temp3;
typedef mtg::Int <1>                    temp4;
typedef temp3::value< temp4 >::res      temp2;
typedef temp1::value< temp2 >::res      res;

Which is very verbose, but allows us to isolate the cases where we need to put the 'typename' keyword.

Specialisation in a structure

The problem

The following code:

let fmatch = 
           function 1 -> 2
                  | _ -> 1
in fmatch 5;;

is translated in the following way:

mtg_open0(let)
  mtg_open(typename, _T, fmatch)
    typedef mtg::Int <1>        res;
  mtg_close
  template<>
  mtg_open0(fmatch< mtg::Int< 1 > >)
    typedef mtg::Int <2>        res;
  mtg_close
  typedef mtg_apply(fmatch, mtg::Int <5>)       res;
mtg_close
typedef let::__::res res;

When trying to compile this, como says: 'error: explicit specialization is not allowed in the current scope' C++ doesn't allow template specialization in structures. This is a very bad news which completly breaks our way translating pattern matchings...

Late night comment about this issue

According to the C++ standard, partial specialisations (template < ... >) are allowed as class members, wether explicit specializations (template <>) are not.

This is why the following code does not compile.

struct foo
{
  template < class T >
  class bar;
  
  template <>
  class bar < int >
  {};
};

int main ()
{
  foo :: bar < int > b;
}

However, there is a tricky solution :

class bogus
{};

struct foo
{
  template < class T, class Bogus = bogus >
  class bar;
  
  template < class Bogus >
  class bar < int, Bogus >
  {};
};

int main ()
{
  foo :: bar < int > b;
}

This code is equivalent to the previous snippet and compiles properly. This solution is now used everywhere in the current implementation of Metagene.

-- FrancisMaes? - 19 Nov 2003


MetaGeneZone


to top

You are here: Projects > MetaGeneHorrorShow

to top

Copyright © 1999-2010 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback