legal code?

Discussion in 'C++' started by Noah Roberts, Dec 10, 2008.

  1. Noah Roberts

    Noah Roberts Guest

    Someone in another list posted this code. It compiles in G++ and
    apparently is absorbed by comeau as well. VS vomits.

    #include <cstddef>

    template < typename T, std :: size_t sz >
    struct Block
    {
    typedef T type[ sz ][ sz ];
    };

    template < typename T >
    void assign( T & assignee, const T & value )
    {}

    template < typename T, std :: size_t sz >
    void assign( T ( & assignee )[ sz ], const T ( & value )[ sz ] )
    {}

    int main( )
    {
    Block< int, 16 > :: type a;
    const Block< int, 16 > :: type b = { };

    assign( a, b );
    }


    1>e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(22)
    : error C2782: 'void assign(T (&)[sz],const T (&)[sz])' : template
    parameter 'T' is ambiguous
    1>
    e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(14)
    : see declaration of 'assign'
    1> could be 'const int [16]'
    1> or 'int [16]'
    1>e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(22)
    : error C2782: 'void assign(T &,const T &)' : template parameter 'T' is
    ambiguous
    1>
    e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(10)
    : see declaration of 'assign'
    1> could be 'const int [16][16]'
    1> or 'int [16][16]'


    G++ compiles and calls the T[] version.
    Noah Roberts, Dec 10, 2008
    #1
    1. Advertising

  2. Noah Roberts

    James Kanze Guest

    On Dec 10, 7:24 pm, Noah Roberts <> wrote:
    > Someone in another list posted this code. It compiles in G++
    > and apparently is absorbed by comeau as well. VS vomits.


    > #include <cstddef>


    > template < typename T, std :: size_t sz >
    > struct Block
    > {
    > typedef T type[ sz ][ sz ];
    > };


    > template < typename T >
    > void assign( T & assignee, const T & value )
    > {}


    > template < typename T, std :: size_t sz >
    > void assign( T ( & assignee )[ sz ], const T ( & value )[ sz ] )
    > {}


    > int main( )
    > {
    > Block< int, 16 > :: type a;
    > const Block< int, 16 > :: type b = { };
    >
    > assign( a, b );
    > }


    > 1>e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(22)
    > : error C2782: 'void assign(T (&)[sz],const T (&)[sz])' : template
    > parameter 'T' is ambiguous
    > 1>
    > e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(14)
    > : see declaration of 'assign'
    > 1> could be 'const int [16]'
    > 1> or 'int [16]'
    > 1>e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(22)
    > : error C2782: 'void assign(T &,const T &)' : template parameter 'T' is
    > ambiguous
    > 1>
    > e:\dev_workspace\experimental\boost_msg_test\boost_msg_test\boost_msg_test.cpp(10)
    > : see declaration of 'assign'
    > 1> could be 'const int [16][16]'
    > 1> or 'int [16][16]'


    > G++ compiles and calls the T[] version.


    It's a bug in VC++. Both function templates should be
    instantiated (and the error message suggests they are) and
    participate in overload resolution, but according to §14.5.5.2,
    the second is clearly more specialized than the first, and
    according to §13.3.3, if all other things are equal (and they
    are, or at least they should be), the function instantiated from
    the more specialized template is chosen.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Dec 12, 2008
    #2
    1. Advertising

  3. Noah Roberts wrote:
    > Someone in another list posted this code. It compiles in G++ and
    > apparently is absorbed by comeau as well. VS vomits.


    A bug in VS prevents it from deducing the template argument properly in
    situations when const-array types are involved. The problem can be
    easily reproduced with

    template <class T> void foo(T& l, const T& r);

    int main() {
    int l[10];
    const int r[10] = {};
    foo(l, r);
    }

    I.e. the original problem with your code has nothing to do with the fact
    that 'assign' template is overloaded - it is easily reproducible with
    just one template.

    You can override the deduction process by specifying the argument
    explicitly (e.g. 'foo<int[10]>(l, r)' in my example), but, of course,
    this looks pretty ugly as a workaround.

    It is worth noting though that if you use that workaround (i.e. call
    your 'assign' as 'assign<Block< int, 16 > :: type>( a, b )' VS does
    correctly select the more specialized second version of 'assign'.

    --
    Best regards,
    Andrey Tarasevich
    Andrey Tarasevich, Dec 16, 2008
    #3
  4. Noah Roberts

    Noah Roberts Guest

    Andrey Tarasevich wrote:
    > Noah Roberts wrote:
    >> Someone in another list posted this code. It compiles in G++ and
    >> apparently is absorbed by comeau as well. VS vomits.

    >
    > A bug in VS prevents it from deducing the template argument properly in
    > situations when const-array types are involved. The problem can be
    > easily reproduced with
    >
    > template <class T> void foo(T& l, const T& r);
    >
    > int main() {
    > int l[10];
    > const int r[10] = {};
    > foo(l, r);
    > }
    >
    > I.e. the original problem with your code has nothing to do with the fact
    > that 'assign' template is overloaded - it is easily reproducible with
    > just one template.
    >
    > You can override the deduction process by specifying the argument
    > explicitly (e.g. 'foo<int[10]>(l, r)' in my example), but, of course,
    > this looks pretty ugly as a workaround.
    >
    > It is worth noting though that if you use that workaround (i.e. call
    > your 'assign' as 'assign<Block< int, 16 > :: type>( a, b )' VS does
    > correctly select the more specialized second version of 'assign'.
    >


    Thanks. I actually helped the guy figure this out a while back. I
    think that MSVC is deducing "T" as "int[]" and then calling THAT
    const...and not doing so correctly (in that it would cascade down to int
    instead of int[]). My reply to them explaining this:

    Noah Roberts wrote:



    > In int const x[5][5], the int contained within the dual array is the

    constant. In the case of T const& value[] though it is T that is const,
    which is an array. This is nonsense I believe (arrays are always
    r-values). VS seems to have no way to handle it while the others do.

    I think this is a bug in VS.

    At first I thought that what I was doing and what you are doing where
    different because you had a typedef int[size][size] that you later
    declare a const object of. I thought maybe this actually made the
    *array* const but I was mistaken. The standard quite clearly states,
    with example, that even when you are doing that to a typedef of array
    type...the const applies to the elements, not to the array. The
    provided example from 8.3.4/1:

    typedef int A[5], AA[2][3];
    typedef const A CA; // type is "array of 5 const int"
    typedef const AA CAA; // type is "array of 2 array of 3 const int"

    It doesn't get less ambiguous than that.

    That means, to me, that even when T is an array type, expecting a const
    reference of that type should resolve in the same manner and your
    template should resolve. As someone mentioned in comp.lang.c++ your
    second version (the one expecting an array) is a closer match and should
    be the one used.

    I think there's a bug in msvc in template typing. I'd bet that it's
    considering const T (&ref)[size] to be an /array of const array of int/
    when passed an /array of array of const int/, which is nonsense in C++
    and would never resolve to anything.

    My answer to their immediate problem:

    Don't recall if it was said already but you can also explicitly say
    which type you're using:

    int main( )
    {
    Block< int, 16 > :: type a;
    const Block< int, 16 > :: type b = { };

    assign<int[16]>( a, b );
    }

    Then you'll need to establish template metaprograms to remove one array
    level from a type and get the type beneath in order to write your
    recursive template call so that it can cast the next level:

    template < typename T >
    struct next_level
    {
    typedef T type;
    };

    template < typename T, size_t sz >
    struct next_level<T[sz]>
    {
    typedef T type;
    };

    template < typename T >
    void assign( T & assignee, const T & value )
    {
    assignee = value;
    }
    template < typename T, std :: size_t sz >
    void assign( T ( & assignee )[ sz ], const T ( & value )[ sz ] )
    {
    for (size_t i = 0; i < sz; ++i)
    assign<typename next_level<T>::type>(assignee, value);
    }


    Tested and works in msvc:


    int main( )
    {
    typedef Block<int,3>::type type_t;
    type_t a;
    type_t const b = { { 1,2,3}, {4,5,6}, {7,8,9} };

    assign<int[3]>( a, b );

    for (int i = 0; i < 3; ++i)
    {
    for (int j = 0; j < 3; ++j)
    std::cout << a[j] << " ";
    std::cout << std::endl;
    }

    std::cin.get();
    }
    Noah Roberts, Dec 16, 2008
    #4
    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. Chris Johnson
    Replies:
    3
    Views:
    446
    C Johnson
    Aug 14, 2003
  2. SenderX
    Replies:
    7
    Views:
    368
    Greg Comeau
    Aug 29, 2003
  3. Ed J

    Is this legal code?

    Ed J, Jun 16, 2004, in forum: C++
    Replies:
    3
    Views:
    545
  4. Jim Ford

    Is this legal C code?

    Jim Ford, Jan 26, 2004, in forum: C Programming
    Replies:
    7
    Views:
    348
    James Hu
    Jan 28, 2004
  5. Ancient_Hacker

    Weird bit of code-- legal???

    Ancient_Hacker, Sep 13, 2006, in forum: C Programming
    Replies:
    29
    Views:
    579
    jaysome
    Sep 15, 2006
Loading...

Share This Page