Inheritance of overloaded vararg methods

Discussion in 'C++' started by RobertEstelle@gmail.com, Dec 15, 2007.

  1. Guest

    Hello,

    I've been banging my head against this problem for a couple hours now
    to no avail.
    I'm trying to make a descendant of a class that has overloaded methods
    with variable argument lists. The problem is, when my descendant class
    does the same, function resolution seems to stop there without looking
    at the base class.

    This happens both with g++ and VS2005, so I don't suspect it's a
    compiler bug.

    Note that I'm just trying to inherit these methods (which are
    overloaded on name), not override their implementation.

    Here's a trivial example:

    /////~ begin code ~/////
    class T1 {};
    class T2 {};

    class A
    {
    public:
    int Get(T1&, char const*, ...);
    int Get(double&, char const*, ...);
    };

    class B : public A
    {
    public:
    int Get(T2&, char const*, ...);
    int Get(int&, char const*, ...);
    };

    int main(int argc, char** argv)
    {
    B b;
    T1 t1;
    // Would expect it to call A::Get(T1&, char const*, ...);
    // but it doesn't; it errors out saying that B::(T2&, char
    const*, ...)
    // can't cast the first operator.
    return b.Get(t1, "Foo", 15);
    }
    /////~ end code ~/////

    The actual error message g++ puts out is:
    vatest.cpp: In function `int main(int, char**)':
    vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    const char[5])'
    vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    vatest.cpp:15: note: int B::Get(int&, const char*, ...)

    This seems pretty puzzling to me -- it doesn't even look at the
    methods A provides!
    If I declare all of A's methods in B (e.g., if I were to make them
    virtual and provide my own implementations in every overriding class),
    resolution works just fine; but then I'm left with the problem of
    implementing them all by manually passing a va_list to the
    base...something that seems very hacky and dangerous.

    Can anyone shed some light on this?

    Thanks,
    Robert Estelle
     
    , Dec 15, 2007
    #1
    1. Advertising

  2. * :
    > Hello,
    >
    > I've been banging my head against this problem for a couple hours now
    > to no avail.
    > I'm trying to make a descendant of a class that has overloaded methods
    > with variable argument lists. The problem is, when my descendant class
    > does the same, function resolution seems to stop there without looking
    > at the base class.
    >
    > This happens both with g++ and VS2005, so I don't suspect it's a
    > compiler bug.
    >
    > Note that I'm just trying to inherit these methods (which are
    > overloaded on name), not override their implementation.
    >
    > Here's a trivial example:
    >
    > /////~ begin code ~/////
    > class T1 {};
    > class T2 {};
    >
    > class A
    > {
    > public:
    > int Get(T1&, char const*, ...);
    > int Get(double&, char const*, ...);
    > };
    >
    > class B : public A
    > {
    > public:
    > int Get(T2&, char const*, ...);
    > int Get(int&, char const*, ...);
    > };
    >
    > int main(int argc, char** argv)
    > {
    > B b;
    > T1 t1;
    > // Would expect it to call A::Get(T1&, char const*, ...);
    > // but it doesn't; it errors out saying that B::(T2&, char
    > const*, ...)
    > // can't cast the first operator.
    > return b.Get(t1, "Foo", 15);
    > }
    > /////~ end code ~/////
    >
    > The actual error message g++ puts out is:
    > vatest.cpp: In function `int main(int, char**)':
    > vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > const char[5])'
    > vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > vatest.cpp:15: note: int B::Get(int&, const char*, ...)
    >
    > This seems pretty puzzling to me -- it doesn't even look at the
    > methods A provides!
    > If I declare all of A's methods in B (e.g., if I were to make them
    > virtual and provide my own implementations in every overriding class),
    > resolution works just fine; but then I'm left with the problem of
    > implementing them all by manually passing a va_list to the
    > base...something that seems very hacky and dangerous.
    >
    > Can anyone shed some light on this?


    It's often a good idea to look at the FAQ before posting.

    <url:
    http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9>.

    Cheers, & hth.,

    - Alf

    --
    A: Because it messes up the order in which people normally read text.
    Q: Why is it such a bad thing?
    A: Top-posting.
    Q: What is the most annoying thing on usenet and in e-mail?
     
    Alf P. Steinbach, Dec 15, 2007
    #2
    1. Advertising

  3. Guest

    On Dec 14, 8:08 pm, "Alf P. Steinbach" <> wrote:
    > * :
    >
    > > Hello,

    >
    > > I've been banging my head against this problem for a couple hours now
    > > to no avail.
    > > I'm trying to make a descendant of a class that has overloaded methods
    > > with variable argument lists. The problem is, when my descendant class
    > > does the same, function resolution seems to stop there without looking
    > > at the base class.

    >
    > > This happens both with g++ and VS2005, so I don't suspect it's a
    > > compiler bug.

    >
    > > Note that I'm just trying to inherit these methods (which are
    > > overloaded on name), not override their implementation.

    >
    > > Here's a trivial example:

    >
    > > /////~ begin code ~/////
    > > class T1 {};
    > > class T2 {};

    >
    > > class A
    > > {
    > > public:
    > > int Get(T1&, char const*, ...);
    > > int Get(double&, char const*, ...);
    > > };

    >
    > > class B : public A
    > > {
    > > public:
    > > int Get(T2&, char const*, ...);
    > > int Get(int&, char const*, ...);
    > > };

    >
    > > int main(int argc, char** argv)
    > > {
    > > B b;
    > > T1 t1;
    > > // Would expect it to call A::Get(T1&, char const*, ...);
    > > // but it doesn't; it errors out saying that B::(T2&, char
    > > const*, ...)
    > > // can't cast the first operator.
    > > return b.Get(t1, "Foo", 15);
    > > }
    > > /////~ end code ~/////

    >
    > > The actual error message g++ puts out is:
    > > vatest.cpp: In function `int main(int, char**)':
    > > vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > > const char[5])'
    > > vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > > vatest.cpp:15: note: int B::Get(int&, const char*, ...)

    >
    > > This seems pretty puzzling to me -- it doesn't even look at the
    > > methods A provides!
    > > If I declare all of A's methods in B (e.g., if I were to make them
    > > virtual and provide my own implementations in every overriding class),
    > > resolution works just fine; but then I'm left with the problem of
    > > implementing them all by manually passing a va_list to the
    > > base...something that seems very hacky and dangerous.

    >
    > > Can anyone shed some light on this?

    >
    > It's often a good idea to look at the FAQ before posting.
    >
    > <url:http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9>.
    >
    > Cheers, & hth.,
    >
    > - Alf
    >
    > --
    > A: Because it messes up the order in which people normally read text.
    > Q: Why is it such a bad thing?
    > A: Top-posting.
    > Q: What is the most annoying thing on usenet and in e-mail?


    Thanks for the link.
    The solution is to put 'using A::Get;' in B's class declaration.

    As an aside - had I gotten any such warning as the FAQ mentions
    ("Warning: Derived::f(char) hides Base::f(double)"), I would have come
    across it in my searching; the problem was, I got no warning from
    either VS2005 or gcc with -Wall, only the compile error I included in
    my post.

    Thanks again for your help.

    - Robert
     
    , Dec 15, 2007
    #3
  4. Pete Becker Guest

    On 2007-12-15 01:56:47 -0500, said:

    >>
    >>> The actual error message g++ puts out is:
    >>> vatest.cpp: In function `int main(int, char**)':
    >>> vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    >>> const char[5])'
    >>> vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    >>> vatest.cpp:15: note: int B::Get(int&, const char*, ...)

    >>
    >>> This seems pretty puzzling to me -- it doesn't even look at the
    >>> methods A provides!

    >
    > Thanks for the link.
    > The solution is to put 'using A::Get;' in B's class declaration.
    >
    > As an aside - had I gotten any such warning as the FAQ mentions
    > ("Warning: Derived::f(char) hides Base::f(double)"), I would have come
    > across it in my searching; the problem was, I got no warning from
    > either VS2005 or gcc with -Wall, only the compile error I included in
    > my post.
    >


    Right. Compilers are professional tools, not tutorials. You got the
    problem exactly right: the compiler doesn't look at the member
    functions that A provides. You didn't know why that was the case. Now
    you do, and you'll know how to interpret similar error messages in the
    future, without needing lengthy explanations from the compiler.

    And note that a little experimentation would have shown that the
    variable-length argument lists aren't part of the problem.

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)
     
    Pete Becker, Dec 15, 2007
    #4
  5. On Dec 15, 8:53 am, wrote:
    > /////~ begin code ~/////
    > class T1 {};
    > class T2 {};
    >
    > class A
    > {
    > public:
    > int Get(T1&, char const*, ...);
    > int Get(double&, char const*, ...);
    >
    > };
    >
    > class B : public A
    > {
    > public:
    > int Get(T2&, char const*, ...);
    > int Get(int&, char const*, ...);
    >
    > };
    >
    > int main(int argc, char** argv)
    > {
    > B b;
    > T1 t1;
    > // Would expect it to call A::Get(T1&, char const*, ...);
    > // but it doesn't; it errors out saying that B::(T2&, char
    > const*, ...)
    > // can't cast the first operator.
    > return b.Get(t1, "Foo", 15);}
    >
    > /////~ end code ~/////
    >
    > The actual error message g++ puts out is:
    > vatest.cpp: In function `int main(int, char**)':
    > vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > const char[5])'
    > vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > vatest.cpp:15: note: int B::Get(int&, const char*, ...)


    Are reference arguments, okay? Isn't it UB? Because, I couldn't find
    anything about it in the C++ standards and C does not know about
    references.
     
    Abhishek Padmanabh, Dec 15, 2007
    #5
  6. James Kanze Guest

    On Dec 15, 3:35 pm, Abhishek Padmanabh <>
    wrote:
    > On Dec 15, 8:53 am, wrote:


    > > /////~ begin code ~/////
    > > class T1 {};
    > > class T2 {};


    > > class A
    > > {
    > > public:
    > > int Get(T1&, char const*, ...);
    > > int Get(double&, char const*, ...);
    > > };


    > > class B : public A
    > > {
    > > public:
    > > int Get(T2&, char const*, ...);
    > > int Get(int&, char const*, ...);
    > > };


    > > int main(int argc, char** argv)
    > > {
    > > B b;
    > > T1 t1;
    > > // Would expect it to call A::Get(T1&, char const*, ...);
    > > // but it doesn't; it errors out saying that B::(T2&, char
    > > const*, ...)
    > > // can't cast the first operator.
    > > return b.Get(t1, "Foo", 15);}


    > > /////~ end code ~/////


    > > The actual error message g++ puts out is:
    > > vatest.cpp: In function `int main(int, char**)':
    > > vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > > const char[5])'
    > > vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > > vatest.cpp:15: note: int B::Get(int&, const char*, ...)


    > Are reference arguments okay? Isn't it UB? Because, I couldn't
    > find anything about it in the C++ standards and C does not
    > know about references.


    Anything about what? §8.3.5 definitely talks about the
    ellipsis, saying that it can terminate the function parameter
    list. And it doesn't say anything about it introducing
    additional restrictions on the previous arguments, so it
    doesn't.

    There is a restriction on the right most argument (parmN) if
    you use va_start (§18.8/3): "If the parameter parmN is declared
    with a function, array, or reference type, or with a type that
    is not compatible with the type that results when passing an
    argument for which there is no parameter, the behavior is
    undefined." This can't affect his code, however, since the
    right most argument has type char const*.

    --
    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 15, 2007
    #6
  7. On Dec 15, 10:59 pm, James Kanze <> wrote:
    > On Dec 15, 3:35 pm, Abhishek Padmanabh <>
    > wrote:
    > > On Dec 15, 8:53 am, wrote:
    > > > /////~ begin code ~/////
    > > > class T1 {};
    > > > class T2 {};
    > > > class A
    > > > {
    > > > public:
    > > > int Get(T1&, char const*, ...);
    > > > int Get(double&, char const*, ...);
    > > > };
    > > > class B : public A
    > > > {
    > > > public:
    > > > int Get(T2&, char const*, ...);
    > > > int Get(int&, char const*, ...);
    > > > };
    > > > int main(int argc, char** argv)
    > > > {
    > > > B b;
    > > > T1 t1;
    > > > // Would expect it to call A::Get(T1&, char const*, ...);
    > > > // but it doesn't; it errors out saying that B::(T2&, char
    > > > const*, ...)
    > > > // can't cast the first operator.
    > > > return b.Get(t1, "Foo", 15);}
    > > > /////~ end code ~/////
    > > > The actual error message g++ puts out is:
    > > > vatest.cpp: In function `int main(int, char**)':
    > > > vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > > > const char[5])'
    > > > vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > > > vatest.cpp:15: note: int B::Get(int&, const char*, ...)

    > > Are reference arguments okay? Isn't it UB? Because, I couldn't
    > > find anything about it in the C++ standards and C does not
    > > know about references.

    >
    > Anything about what? §8.3.5 definitely talks about the
    > ellipsis, saying that it can terminate the function parameter
    > list. And it doesn't say anything about it introducing
    > additional restrictions on the previous arguments, so it
    > doesn't.
    >
    > There is a restriction on the right most argument (parmN) if
    > you use va_start (§18.8/3): "If the parameter parmN is declared
    > with a function, array, or reference type, or with a type that
    > is not compatible with the type that results when passing an
    > argument for which there is no parameter, the behavior is
    > undefined." This can't affect his code, however, since the
    > right most argument has type char const*.
    >


    Yes, I was not clear about restrictions on previous arguments. So, I
    believe, reference arguments to vararg functions are fine if they are
    not the right most argument before (...). Thanks!
     
    Abhishek Padmanabh, Dec 16, 2007
    #7
  8. James Kanze Guest

    On Dec 16, 5:34 am, Abhishek Padmanabh <>
    wrote:
    > On Dec 15, 10:59 pm, James Kanze <> wrote:


    [...]
    > > There is a restriction on the right most argument (parmN) if
    > > you use va_start (§18.8/3): "If the parameter parmN is declared
    > > with a function, array, or reference type, or with a type that
    > > is not compatible with the type that results when passing an
    > > argument for which there is no parameter, the behavior is
    > > undefined." This can't affect his code, however, since the
    > > right most argument has type char const*.


    > Yes, I was not clear about restrictions on previous arguments. So, I
    > believe, reference arguments to vararg functions are fine if they are
    > not the right most argument before (...). Thanks!


    They're also fine if you don't use va_start in the function.
    Not very useful, of course, but legal:).

    --
    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 16, 2007
    #8
  9. Guest

    On Dec 15, 5:55 am, Pete Becker <> wrote:
    > On 2007-12-15 01:56:47 -0500, said:
    >
    >
    >
    >
    >
    > >>> The actual error message g++ puts out is:
    > >>> vatest.cpp: In function `int main(int, char**)':
    > >>> vatest.cpp:25: error: no matching function for call to `B::Get(T1&,
    > >>> const char[5])'
    > >>> vatest.cpp:14: note: candidates are: int B::Get(T2&, const char*, ...)
    > >>> vatest.cpp:15: note: int B::Get(int&, const char*, ...)

    >
    > >>> This seems pretty puzzling to me -- it doesn't even look at the
    > >>> methods A provides!

    >
    > > Thanks for the link.
    > > The solution is to put 'using A::Get;' in B's class declaration.

    >
    > > As an aside - had I gotten any such warning as the FAQ mentions
    > > ("Warning: Derived::f(char) hides Base::f(double)"), I would have come
    > > across it in my searching; the problem was, I got no warning from
    > > either VS2005 or gcc with -Wall, only the compile error I included in
    > > my post.

    >
    > Right. Compilers are professional tools, not tutorials. You got the
    > problem exactly right: the compiler doesn't look at the member
    > functions that A provides. You didn't know why that was the case. Now
    > you do, and you'll know how to interpret similar error messages in the
    > future, without needing lengthy explanations from the compiler.
    >
    > And note that a little experimentation would have shown that the
    > variable-length argument lists aren't part of the problem.
    >
    > --
    > Pete
    > Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    > Standard C++ Library Extensions: a Tutorial and Reference
    > (www.petebecker.com/tr1book)


    Quite right - I realized that I should have narrowed the test down to
    see if the varargs actually had anything to do with it, soon after
    posting. Once I got back to a computer, Alf had already found the
    solution.
     
    , Dec 17, 2007
    #9
    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. samwyse
    Replies:
    11
    Views:
    417
    samwyse
    Jul 12, 2007
  2. Mister B
    Replies:
    5
    Views:
    730
    Kenny McCormack
    May 15, 2009
  3. Jamis Buck

    [RDOC] patch for vararg require

    Jamis Buck, Nov 4, 2004, in forum: Ruby
    Replies:
    2
    Views:
    120
    Jamis Buck
    Nov 4, 2004
  4. Replies:
    3
    Views:
    174
    Phlip
    Jul 25, 2007
  5. Kenneth McDonald
    Replies:
    5
    Views:
    324
    Kenneth McDonald
    Sep 26, 2008
Loading...

Share This Page