overloading on the template parameter arity of a template templateparameter

Discussion in 'C++' started by Howard Gardner, Jul 19, 2006.

  1. // I think that there is no way to write the template "cant_write_me" in
    // this example. Would love to be wrong.

    // one of many approaches that won't work
    template< template< typename > class > struct cant_write_me{};
    template< template< typename, typename > class > struct cant_write_me{};

    template< typename > struct arity_one{};
    template< typename, typename > struct arity_two{};

    cant_write_me< arity_one > instantiated_arity_one;
    cant_write_me< arity_two > instantiated_arity_two;
     
    Howard Gardner, Jul 19, 2006
    #1
    1. Advertising

  2. Re: overloading on the template parameter arity of a template template parameter

    Howard Gardner wrote:
    > // I think that there is no way to write the template "cant_write_me"
    > in // this example. Would love to be wrong.
    >
    > // one of many approaches that won't work
    > template< template< typename > class > struct cant_write_me{};
    > template< template< typename, typename > class > struct
    > cant_write_me{};


    'cant_write_me' here cannot be used because it's not a specialisation of
    the original template. The name has to be unique or it has to be some
    kind of specialisation (which requires the <> after the name).

    > template< typename > struct arity_one{};
    > template< typename, typename > struct arity_two{};
    >
    > cant_write_me< arity_one > instantiated_arity_one;
    > cant_write_me< arity_two > instantiated_arity_two;


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jul 19, 2006
    #2
    1. Advertising

  3. Victor Bazarov wrote:
    > Howard Gardner wrote:
    >> // I think that there is no way to write the template "cant_write_me"
    >> in // this example. Would love to be wrong.
    >>
    >> // one of many approaches that won't work
    >> template< template< typename > class > struct cant_write_me{};
    >> template< template< typename, typename > class > struct
    >> cant_write_me{};

    >
    > 'cant_write_me' here cannot be used because it's not a specialisation of
    > the original template. The name has to be unique or it has to be some
    > kind of specialisation (which requires the <> after the name).
    >
    >> template< typename > struct arity_one{};
    >> template< typename, typename > struct arity_two{};
    >>
    >> cant_write_me< arity_one > instantiated_arity_one;
    >> cant_write_me< arity_two > instantiated_arity_two;

    >
    > V


    I know :)

    I've tried a large number of approaches that use specializations. I've
    gotten very creative. I think that there simply is no way to write
    cant_write_me.

    I ran across it because I was trying to write a facility to use like this:

    template_arity_of< class-template-identifier >::value

    I did in fact manage to solve that problem, but the solution is pretty
    unloveable. I have to write

    template_arity_of
    <
    MACRO( class-template-identifier )
    >::value


    that solution looks like:

    #include <ostream>
    #include <cstddef>

    typedef char no;
    struct yes{ no value[2]; };

    template< template< typename > class >
    yes test_1();

    template< template< typename, typename > class >
    no test_1();

    template< template< typename > class >
    no test_2();

    template< template< typename, typename > class >
    yes test_2();

    template< size_t, size_t >
    struct template_arity_of;

    template< >
    struct template_arity_of< sizeof( yes ), sizeof( no ) >
    {
    static const size_t value = 1;
    };

    template< >
    struct template_arity_of< sizeof( no ), sizeof( yes ) >
    {
    static const size_t value = 2;
    };

    #define MACRO( template_class_id ) \
    sizeof( test_1< template_class_id >() ),\
    sizeof( test_2< template_class_id >() )

    template< typename > struct arity_one;
    template< typename, typename > struct arity_two;

    int
    main()
    {
    using namespace std;
    cout << template_arity_of< MACRO( arity_one ) >::value << endl;
    cout << template_arity_of< MACRO( arity_two ) >::value << endl;
    }

    There're two really vile problems with this solution.

    First, if N is the largest arity that I test for, implementing this
    solution requires 2*N*N + N bits of syntax.

    Second, there's the macro. It's there for three reasons. First, a
    straight use requires N bits of syntax. Second, those bits of syntax are
    very likely to contain a bug. Third, it's pretty obvious that N will
    grow and it would be bad to have to rewrite all the uses.

    I'm looking into another variation of the sizeof trick (sometimes used
    for a restricted typeof) which would let me implement a less hateful
    kludge, but I'd much rather learn that there's some way to write
    "cant_write_me" after all.
     
    Howard Gardner, Jul 19, 2006
    #3
  4. Howard Gardner

    Arkadiy Guest

    Re: overloading on the template parameter arity of a template template parameter

    Howard Gardner wrote:

    > template_arity_of
    > <
    > MACRO( class-template-identifier )
    > >::value


    What about

    TEMPLATE_ARITY_OF(class-template-identifier)

    ?

    This is almost a religious issue. People hate macros, but I think the
    reasons are related to macro usage that hides the runtime code. In a
    compile-time facility like this, macros compliment template
    meta-programming in the areas where it's not that great -- variable
    number of template/function parameters.

    > First, if N is the largest arity that I test for, implementing this
    > solution requires 2*N*N + N bits of syntax.


    Just use the Boost.Preprocessor library and have it generate these bits
    of syntax for you.

    Regards,
    Arkadiy
     
    Arkadiy, Jul 19, 2006
    #4
  5. Arkadiy wrote:
    > Howard Gardner wrote:
    >
    >> template_arity_of
    >> <
    >> MACRO( class-template-identifier )
    >> >::value

    >
    > What about
    >
    > TEMPLATE_ARITY_OF(class-template-identifier)
    >
    > ?
    >
    > This is almost a religious issue. People hate macros, but I think the
    > reasons are related to macro usage that hides the runtime code. In a
    > compile-time facility like this, macros compliment template
    > meta-programming in the areas where it's not that great -- variable
    > number of template/function parameters.
    >
    >> First, if N is the largest arity that I test for, implementing this
    >> solution requires 2*N*N + N bits of syntax.

    >
    > Just use the Boost.Preprocessor library and have it generate these bits
    > of syntax for you.


    I sure don't want to fight a battle in the macros holy war :)

    I prefer not to use them, but sometimes using them is better. I think
    that was a pretty clear case, and it was even clearer in the real code
    where N was 8 right off the bat.

    I macrod the template parameter syntax rather than the whole invocation
    because that was enough to encapsulate the cruft.

    I didn't use the Boost.Preprocessor library because I don't know it.
    When I do eventually grapple with it, it will probably be because I want
    to read the boost source code (Function, Lambda, TypeTraits, and MPL)
    and not because I actually want to use it.

    I got the other solution working. It looks like this:

    #include <ostream>
    #include <cstddef>

    typedef char t01[1];
    template< template< typename > class >
    t01 * test();

    typedef char t02[2];
    template< template< typename, typename > class >
    t02 * test();

    template< size_t xSize >
    struct template_arity_of
    {
    static const size_t value = xSize;
    };

    template< typename > struct arity_one;
    template< typename, typename > struct arity_two;

    int
    main()
    {
    using namespace std;

    cout
    << template_arity_of< sizeof( * test< arity_one >() ) >::value
    << endl;

    cout
    << template_arity_of< sizeof( * test< arity_two >() ) >::value
    << endl;
    }

    It's better, but the invocation syntax is still ugly. It's tempting to
    macro it, but in this case I'll probably refrain.

    The situation is different than it was because the old reasons don't
    apply anymore:

    1) It's not horrifically long.

    2) It's not particularly likely that someone will accidentally write
    something that compiles but doesn't work.

    3) Even though N will grow, the existing syntax won't have to change.

    4) (I failed to mention this when I was apologizing for the macro in the
    previous rendition) I don't think I'd use the macro personally.

    The new temptation actually comes from the fact that I WANT to change
    the invocation syntax, and will do it the very INSTANT that I can find
    better syntax.
     
    Howard Gardner, Jul 20, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Michael Feathers
    Replies:
    3
    Views:
    296
    Roland Pibinger
    Aug 4, 2006
  2. Stuart Redmann
    Replies:
    5
    Views:
    535
    Stuart Redmann
    Dec 14, 2007
  3. ðÅÔÒÏ× áÌÅËÓÁÎÄÒ

    Why the expression "(1)" is not an one-arity tuple, but int ?

    ðÅÔÒÏ× áÌÅËÓÁÎÄÒ, Dec 4, 2009, in forum: Python
    Replies:
    0
    Views:
    288
    ðÅÔÒÏ× áÌÅËÓÁÎÄÒ
    Dec 4, 2009
  4. Jeff Mitchell

    getting the arity

    Jeff Mitchell, Aug 28, 2003, in forum: Ruby
    Replies:
    1
    Views:
    117
    Harry Ohlsen
    Aug 28, 2003
  5. Simon Strandgaard
    Replies:
    4
    Views:
    126
    Dan Doel
    Oct 29, 2003
Loading...

Share This Page