Overloading a template member function with a dependent name

Discussion in 'C++' started by mlimber, May 20, 2011.

  1. mlimber

    mlimber Guest

    I'm trying to overload a template member function with a dependent
    name involved. The following does not work as I'd like:

    class C
    {
    public:
    template<class Iter>
    void Foo( Iter )
    {
    std::cout << "Normal\n";
    }

    template<class T, std::size_t N>
    void Foo( typename std::tr1::array<T,N>::iterator )
    {
    std::cout << "Special\n";
    }
    };

    int main()
    {
    C c;
    std::tr1::array<int,10> a1;
    c.Foo( a1.begin() ); // Doesn't print "Special"!
    }

    How can I get that last line in main() to invoke the special C::Foo()?
    mlimber, May 20, 2011
    #1
    1. Advertising

  2. mlimber

    mlimber Guest

    On May 20, 4:37 pm, mlimber <> wrote:
    [snip]
    >    template<class T, std::size_t N>
    >    void Foo( typename std::tr1::array<T,N>::iterator )

    [snip]

    One additional note: I can't use T* as a work-around here because in
    VS2010's implementation, std::tr1::array<T,N>::iterator is the
    internal type "_Array_iterator<_Ty, _Size>", which is a checked
    iterator (at least in debug mode).

    Cheers! --M
    mlimber, May 20, 2011
    #2
    1. Advertising

  3. mlimber

    mlimber Guest

    On May 20, 5:21 pm, "Alf P. Steinbach /Usenet" <alf.p.steinbach
    > wrote:
    > * mlimber, on 20.05.2011 22:37:
    > > I'm trying to overload a template member function with a dependent
    > > name involved. The following does not work as I'd like:

    >
    > >   class C
    > >   {
    > >   public:
    > >     template<class Iter>
    > >     void Foo( Iter )
    > >     {
    > >       std::cout<<  "Normal\n";
    > >     }

    >
    > >     template<class T, std::size_t N>
    > >     void Foo( typename std::tr1::array<T,N>::iterator )
    > >     {
    > >       std::cout<<  "Special\n";
    > >     }
    > >   };

    >
    > >   int main()
    > >   {
    > >     C c;
    > >     std::tr1::array<int,10>  a1;
    > >     c.Foo( a1.begin() ); // Doesn't print "Special"!
    > >   }

    >
    > > How can I get that last line in main() to invoke the special C::Foo()?

    >
    > Why there is a problem:
    >
    > <code>
    >      template< class Type >
    >      struct Foo
    >      {
    >          typedef int     T;
    >      };
    >
    >      template< class Type >
    >      void foo( typename Type::T ) {}
    >
    >      int main()
    >      {
    >          foo( 666 );     // !Nope
    >      }
    > </code>
    >
    > This does not compile because the compiler cannot deduce the template parameter.
    > It cannot because it would be an unbounded reverse lookup: given the actual
    > argument type `int`, find the type `Type` that has a member typedef of `T` with
    > type `int`. There can be zillions or none of such types.
    >
    > There are techniques that sometimes can be used to still do something /like/ you
    > seem to be aiming for.
    >
    > One crucial question for applicability of such techniques here is N: do you need
    > to know it? In that case I don't know any solution other than changing the
    > design. I don't think it can be inferred from the iterator type, at all.


    Thanks, Alf. I don't need N (it would be sugar to have it, but since
    I'm actually passing in begin and end, I can calculate it). So do
    tell!

    Cheers! --M
    mlimber, May 20, 2011
    #3
  4. * mlimber, on 20.05.2011 22:37:
    > I'm trying to overload a template member function with a dependent
    > name involved. The following does not work as I'd like:
    >
    > class C
    > {
    > public:
    > template<class Iter>
    > void Foo( Iter )
    > {
    > std::cout<< "Normal\n";
    > }
    >
    > template<class T, std::size_t N>
    > void Foo( typename std::tr1::array<T,N>::iterator )
    > {
    > std::cout<< "Special\n";
    > }
    > };
    >
    > int main()
    > {
    > C c;
    > std::tr1::array<int,10> a1;
    > c.Foo( a1.begin() ); // Doesn't print "Special"!
    > }
    >
    > How can I get that last line in main() to invoke the special C::Foo()?


    Why there is a problem:

    <code>
    template< class Type >
    struct Foo
    {
    typedef int T;
    };

    template< class Type >
    void foo( typename Type::T ) {}

    int main()
    {
    foo( 666 ); // !Nope
    }
    </code>

    This does not compile because the compiler cannot deduce the template parameter.
    It cannot because it would be an unbounded reverse lookup: given the actual
    argument type `int`, find the type `Type` that has a member typedef of `T` with
    type `int`. There can be zillions or none of such types.

    There are techniques that sometimes can be used to still do something /like/ you
    seem to be aiming for.

    One crucial question for applicability of such techniques here is N: do you need
    to know it? In that case I don't know any solution other than changing the
    design. I don't think it can be inferred from the iterator type, at all.


    Cheers & hth.,

    - Alf "hungry"

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, May 20, 2011
    #4
  5. * mlimber, on 20.05.2011 23:21:
    > On May 20, 5:21 pm, "Alf P. Steinbach /Usenet"<alf.p.steinbach
    > > wrote:
    >> * mlimber, on 20.05.2011 22:37:
    >>> I'm trying to overload a template member function with a dependent
    >>> name involved. The following does not work as I'd like:

    >>
    >>> class C
    >>> {
    >>> public:
    >>> template<class Iter>
    >>> void Foo( Iter )
    >>> {
    >>> std::cout<< "Normal\n";
    >>> }

    >>
    >>> template<class T, std::size_t N>
    >>> void Foo( typename std::tr1::array<T,N>::iterator )
    >>> {
    >>> std::cout<< "Special\n";
    >>> }
    >>> };

    >>
    >>> int main()
    >>> {
    >>> C c;
    >>> std::tr1::array<int,10> a1;
    >>> c.Foo( a1.begin() ); // Doesn't print "Special"!
    >>> }

    >>
    >>> How can I get that last line in main() to invoke the special C::Foo()?

    >>
    >> Why there is a problem:
    >>
    >> <code>
    >> template< class Type>
    >> struct Foo
    >> {
    >> typedef int T;
    >> };
    >>
    >> template< class Type>
    >> void foo( typename Type::T ) {}
    >>
    >> int main()
    >> {
    >> foo( 666 ); // !Nope
    >> }
    >> </code>
    >>
    >> This does not compile because the compiler cannot deduce the template parameter.
    >> It cannot because it would be an unbounded reverse lookup: given the actual
    >> argument type `int`, find the type `Type` that has a member typedef of `T` with
    >> type `int`. There can be zillions or none of such types.
    >>
    >> There are techniques that sometimes can be used to still do something /like/ you
    >> seem to be aiming for.
    >>
    >> One crucial question for applicability of such techniques here is N: do you need
    >> to know it? In that case I don't know any solution other than changing the
    >> design. I don't think it can be inferred from the iterator type, at all.

    >
    > Thanks, Alf. I don't need N (it would be sugar to have it, but since
    > I'm actually passing in begin and end, I can calculate it). So do
    > tell!


    Uh, I don't have a suitable implementation to test with, since the g++ 4.4.1
    tr1/array has just raw pointers as iterators. Not much can be deduced from a raw
    pointer type! But as an example of some of the ideas,


    <code>
    #include <iterator>
    #include <iostream>
    #include <tr1/array>
    #include <vector>

    #ifdef FOR_REAL
    template< class Type, int n >
    struct MyArray
    : std::tr1::array< Type, n >
    {};
    #else
    template< class Type, int n >
    struct MyArray
    {
    Type data;

    typedef std::iterator< std::random_access_iterator_tag, Type >
    iterator;
    iterator begin() { return iterator(); }
    Type& operator[]( int i ) { return data; }
    };
    #endif

    template< class A, class B > struct IsSameType{ enum { yes = false }; };
    template< class Type > struct IsSameType< Type, Type >{ enum { yes = true }; };

    #define STATIC_ASSERT( e ) typedef char shouldBeTrue[(e)?1:-1]
    STATIC_ASSERT(
    !(IsSameType<
    std::vector<int>::iterator,
    MyArray<int, 10>::iterator
    >::yes)

    );
    STATIC_ASSERT(
    !(IsSameType<
    int*,
    MyArray<int, 10>::iterator
    >::yes)

    );

    namespace detail {
    struct AGeneralIter {};
    struct ASpecialIter {};

    template< class Iter, class Pointee >
    struct IteratorCategory
    {
    typedef AGeneralIter T;
    };

    // These can possibly be generated by the Boost macro repeat support.

    template< class Pointee >
    struct IteratorCategory< typename MyArray< Pointee, 10 >::iterator,
    Pointee >
    {
    typedef ASpecialIter T;
    };
    } // namespace detail

    class C
    {
    private:

    template< class IterCategory, class Iter > struct Impl;

    template< class Iter >
    struct Impl< detail::AGeneralIter, Iter >
    {
    static void foo( Iter )
    {
    std::cout << "Normal\n";
    }
    };

    template< class Iter >
    struct Impl< detail::ASpecialIter, Iter >
    {
    static void foo( Iter )
    {
    std::cout << "Special\n";
    }
    };

    public:
    template< class Iter >
    void foo( Iter it )
    {
    typedef typename std::iterator_traits< Iter >::value_type
    Pointee;
    typedef typename detail::IteratorCategory< Iter, Pointee >::T
    Category;

    Impl< Category, Iter >::foo( it );
    }
    };

    int main()
    {
    C c;

    MyArray< int, 10 > a1;
    c.foo( &a1[0] ); // If the code compiles, prints "Normal".
    c.foo( a1.begin() ); // If the code compiles, prints "Special".
    }
    </code>


    Simply define FOR_REAL to check how it fares for your tr1/array implementation.

    Or, at least I hope that that's possible; naturally I haven't been able to test
    that! ;-)


    Cheers, & sorry but on 2nd thought I don't think this helps with imm. prob.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, May 21, 2011
    #5
  6. mlimber

    Ruben Safir Guest

    mlimber <> wrote:
    > I'm trying to overload a template member function with a dependent
    > name involved. The following does not work as I'd like:
    >
    > class C
    > {
    > public:
    > template<class Iter>
    > void Foo( Iter )
    > {
    > std::cout << "Normal\n";
    > }
    >
    > template<class T, std::size_t N>
    > void Foo( typename std::tr1::array<T,N>::iterator )
    > {
    > std::cout << "Special\n";
    > }
    > };
    >
    > int main()
    > {
    > C c;
    > std::tr1::array<int,10> a1;
    > c.Foo( a1.begin() ); // Doesn't print "Special"!
    > }
    >
    > How can I get that last line in main() to invoke the special C::Foo()?


    Foo is not in your class, and I'm actually surprise this compiles with
    the keyword typename in the parameter list.

    Ruben
    Ruben Safir, May 21, 2011
    #6
  7. * Ruben Safir, on 21.05.2011 01:33:
    > mlimber<> wrote:
    >> I'm trying to overload a template member function with a dependent
    >> name involved. The following does not work as I'd like:
    >>
    >> class C
    >> {
    >> public:
    >> template<class Iter>
    >> void Foo( Iter )
    >> {
    >> std::cout<< "Normal\n";
    >> }
    >>
    >> template<class T, std::size_t N>
    >> void Foo( typename std::tr1::array<T,N>::iterator )
    >> {
    >> std::cout<< "Special\n";
    >> }
    >> };
    >>
    >> int main()
    >> {
    >> C c;
    >> std::tr1::array<int,10> a1;
    >> c.Foo( a1.begin() ); // Doesn't print "Special"!
    >> }
    >>
    >> How can I get that last line in main() to invoke the special C::Foo()?

    >
    > Foo is not in your class, and I'm actually surprise this compiles with
    > the keyword typename in the parameter list.


    Foo is a member of class C which is user defined. The keyword `typename` is
    needed in the parameter list. It should not compile without it.

    Cheers & hth.,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach /Usenet, May 21, 2011
    #7
    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. George2

    non-dependent name in template function

    George2, Mar 10, 2008, in forum: C Programming
    Replies:
    0
    Views:
    295
    George2
    Mar 10, 2008
  2. puzzlecracker
    Replies:
    1
    Views:
    508
    James Kanze
    Aug 7, 2008
  3. Peng Yu
    Replies:
    3
    Views:
    755
    Thomas J. Gritzan
    Oct 26, 2008
  4. Hicham Mouline
    Replies:
    0
    Views:
    423
    Hicham Mouline
    Apr 23, 2009
  5. Hicham Mouline
    Replies:
    1
    Views:
    405
    Michael DOUBEZ
    Apr 24, 2009
Loading...

Share This Page