How do I prevent a function template take precedence over inheritance?

Discussion in 'C++' started by DeMarcus, Apr 23, 2010.

  1. DeMarcus

    DeMarcus Guest

    Hi,

    I have a function template structure like this.

    struct A
    {
    };

    struct B : A
    {
    }

    class SomeClass
    {
    public:

    template<typename T>
    void fnc( const T& t )
    {
    std::cout << "Template" << std::endl;
    }

    void fnc( const A& a )
    {
    std::cout << "Non-template" << std::endl;
    }
    };

    int main()
    {
    SomeClass sc;
    sc.fnc( A() ); // This gives me "Non-template".
    sc.fnc( B() ); // Error! This gives me "Template"
    // even though B inherits from A.
    }

    What's the proper way making instances of B access the non-templated
    function?

    Thanks,
    Daniel
    DeMarcus, Apr 23, 2010
    #1
    1. Advertising

  2. DeMarcus

    pfultz2 Guest

    Re: How do I prevent a function template take precedence overinheritance?

    On Apr 23, 11:00 am, DeMarcus <> wrote:
    > Hi,
    >
    > I have a function template structure like this.
    >
    > struct A
    > {
    >
    > };
    >
    > struct B : A
    > {
    >
    > }
    >
    > class SomeClass
    > {
    > public:
    >
    >     template<typename T>
    >     void fnc( const T& t )
    >     {
    >        std::cout << "Template" << std::endl;
    >     }
    >
    >     void fnc( const A& a )
    >     {
    >        std::cout << "Non-template" << std::endl;
    >     }
    >
    > };
    >
    > int main()
    > {
    >     SomeClass sc;
    >     sc.fnc( A() );  // This gives me "Non-template".
    >     sc.fnc( B() );  // Error! This gives me "Template"
    >                     // even though B inherits from A.
    >
    > }
    >
    > What's the proper way making instances of B access the non-templated
    > function?
    >
    > Thanks,
    > Daniel


    Use enable_if and make them both templates:
    class SomeClass
    {
    public:

    template<typename T>
    void fnc( const T& t, typename enable_if<inherits<T, A> >::type *
    dummy = 0 )
    {
    std::cout << "Inherits A" << std::endl;
    }

    template<typename T>
    void fnc( const T& t )
    {
    std::cout << "Doesnt inherit A" << std::endl;
    }

    };

    You can read about enable_if here: http://www.boost.org/doc/libs/1_42_0/libs/utility/enable_if.html
    pfultz2, Apr 23, 2010
    #2
    1. Advertising

  3. DeMarcus

    DeMarcus Guest

    Victor Bazarov wrote:
    > DeMarcus wrote:
    >> Hi,
    >>
    >> I have a function template structure like this.
    >>
    >> struct A
    >> {
    >> };
    >>
    >> struct B : A
    >> {
    >> }
    >>
    >> class SomeClass
    >> {
    >> public:
    >>
    >> template<typename T>
    >> void fnc( const T& t )
    >> {
    >> std::cout << "Template" << std::endl;
    >> }
    >>
    >> void fnc( const A& a )
    >> {
    >> std::cout << "Non-template" << std::endl;
    >> }
    >> };
    >>
    >> int main()
    >> {
    >> SomeClass sc;
    >> sc.fnc( A() ); // This gives me "Non-template".
    >> sc.fnc( B() ); // Error! This gives me "Template"

    >
    > It's not an error. The template, since it's allowed to be instantiated,
    > participates in the overload resolution. And because the compiler is
    > able to deduce 'T' as 'B' (most likely), its argument conversion
    > (reference binding, which is like the "identity") has a higher rank than
    > the non-template's "derived-to-base" conversion. That's why the
    > compiler picks the template.
    >
    >> // even though B inherits from A.

    >
    > Not "even though" but "because".
    >
    >> }
    >>
    >> What's the proper way making instances of B access the non-templated
    >> function?

    >
    > Use SFINAE, make your template function non-instantiatable for any class
    > that is derived from A. Utilize the 'enable_if' without making both
    > functions templates. Or invent your own way. For example, use the fact
    > that any class that derives from A has a member named 'A', with the same
    > level of access as the base class (public if derived publicly, etc.)
    >



    Ok, thanks!

    Before I saw your post I did a solution like this.

    class SomeClass
    {
    public:

    template<typename T>
    void fnc( const T& t )
    {
    std::cout << "Template" << std::endl;
    }

    void fnc( const A& a )
    {
    std::cout << "Non-template" << std::endl;
    }

    void fnc( const B& b )
    {
    fnc( static_cast<const A&>( b ) );
    }

    };

    Is it bad practice to use static_cast?
    DeMarcus, Apr 23, 2010
    #3
  4. DeMarcus

    DeMarcus Guest

    Victor Bazarov wrote:
    > DeMarcus wrote:
    >> Victor Bazarov wrote:
    >>> DeMarcus wrote:
    >>>> Hi,
    >>>>
    >>>> I have a function template structure like this.
    >>>>
    >>>> struct A
    >>>> {
    >>>> };
    >>>>
    >>>> struct B : A
    >>>> {
    >>>> }
    >>>>
    >>>> class SomeClass
    >>>> {
    >>>> public:
    >>>>
    >>>> template<typename T>
    >>>> void fnc( const T& t )
    >>>> {
    >>>> std::cout << "Template" << std::endl;
    >>>> }
    >>>>
    >>>> void fnc( const A& a )
    >>>> {
    >>>> std::cout << "Non-template" << std::endl;
    >>>> }
    >>>> };
    >>>>
    >>>> int main()
    >>>> {
    >>>> SomeClass sc;
    >>>> sc.fnc( A() ); // This gives me "Non-template".
    >>>> sc.fnc( B() ); // Error! This gives me "Template"
    >>>
    >>> It's not an error. The template, since it's allowed to be
    >>> instantiated, participates in the overload resolution. And because
    >>> the compiler is able to deduce 'T' as 'B' (most likely), its argument
    >>> conversion (reference binding, which is like the "identity") has a
    >>> higher rank than the non-template's "derived-to-base" conversion.
    >>> That's why the compiler picks the template.
    >>>
    >>>> // even though B inherits from A.
    >>>
    >>> Not "even though" but "because".
    >>>
    >>>> }
    >>>>
    >>>> What's the proper way making instances of B access the non-templated
    >>>> function?
    >>>
    >>> Use SFINAE, make your template function non-instantiatable for any
    >>> class that is derived from A. Utilize the 'enable_if' without making
    >>> both functions templates. Or invent your own way. For example, use
    >>> the fact that any class that derives from A has a member named 'A',
    >>> with the same level of access as the base class (public if derived
    >>> publicly, etc.)
    >>>

    >>
    >>
    >> Ok, thanks!
    >>
    >> Before I saw your post I did a solution like this.
    >>
    >> class SomeClass
    >> {
    >> public:
    >>
    >> template<typename T>
    >> void fnc( const T& t )
    >> {
    >> std::cout << "Template" << std::endl;
    >> }
    >>
    >> void fnc( const A& a )
    >> {
    >> std::cout << "Non-template" << std::endl;
    >> }
    >>
    >> void fnc( const B& b )
    >> {
    >> fnc( static_cast<const A&>( b ) );
    >> }
    >>
    >> };
    >>
    >> Is it bad practice to use static_cast?
    >>

    >
    > Bad practice? No. It's fine, and it's elegant.
    >


    Thanks!!!
    DeMarcus, Apr 23, 2010
    #4
  5. Re: How do I prevent a function template take precedence overinheritance?

    On 23 avr, 17:00, DeMarcus <> wrote:
    > Hi,
    >
    > I have a function template structure like this.
    >
    > struct A
    > {
    >
    > };
    >
    > struct B : A
    > {
    >
    > }
    >
    > class SomeClass
    > {
    > public:
    >
    >     template<typename T>
    >     void fnc( const T& t )
    >     {
    >        std::cout << "Template" << std::endl;
    >     }
    >
    >     void fnc( const A& a )
    >     {
    >        std::cout << "Non-template" << std::endl;
    >     }
    >
    > };
    >
    > int main()
    > {
    >     SomeClass sc;
    >     sc.fnc( A() );  // This gives me "Non-template".
    >     sc.fnc( B() );  // Error! This gives me "Template"
    >                     // even though B inherits from A.
    >
    > }
    >
    > What's the proper way making instances of B access the non-templated
    > function?


    Another solution (apart from SFINAE) is to use a proxy class:

    class SomeClass
    {
    public:

    struct Generic
    {
    template<typename T>
    Generic( const T& t )
    {
    std::cout << "Template" << std::endl;
    }
    };

    void fnc( const Generic& g)
    {
    // possibly g.do_fnc(this);
    }

    void fnc( const A& a )
    {
    std::cout << "Non-template" << std::endl;
    }
    };

    But it is not always practical.

    --
    Michael
    Michael Doubez, Apr 24, 2010
    #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. Pete Becker
    Replies:
    5
    Views:
    1,014
    =?iso-8859-1?Q?Ali_=C7ehreli?=
    Nov 19, 2004
  2. Replies:
    1
    Views:
    473
    Victor Bazarov
    Jul 20, 2005
  3. Gaijinco
    Replies:
    5
    Views:
    311
    Gaijinco
    May 29, 2007
  4. Peng Yu
    Replies:
    3
    Views:
    772
    Thomas J. Gritzan
    Oct 26, 2008
  5. Matt Fioravante
    Replies:
    2
    Views:
    241
    Matt Fioravante
    Feb 22, 2013
Loading...

Share This Page