Difficulty declaring free function that takes parameter that is anested member of a class template

Discussion in 'C++' started by Travis Vitek, Jan 19, 2012.

  1. Travis Vitek

    Travis Vitek Guest

    Can someone explain why the compiler is unable to deduce T when
    invoking the function template `f' in the example below? Is there some
    way to get the compiler to see `f' without having to explicitly
    specify the template argument type?

    template <class T>
    struct A {
    enum B {
    };
    };

    template <class T>
    void f(typename A<T>::B a)
    {
    }

    int main ()
    {
    A<int>::B a0 = A<int>::B();
    f(a0); // don't want to explicitly specify f<int>(a0) here
    }

    I have been able to move the definition of `f' into A to get the
    results I want, but I'd like to declare/define the function outside of
    A if possible. Is there something wrong with my declaration of `f', or
    is there some other way to do what I want?

    Travis
     
    Travis Vitek, Jan 19, 2012
    #1
    1. Advertising

  2. Re: Difficulty declaring free function that takes parameter thatis a nested member of a class template

    On 1/18/2012 7:58 PM, Travis Vitek wrote:
    > Can someone explain why the compiler is unable to deduce T when
    > invoking the function template `f' in the example below?


    The answer to that is usually, "Because that is not one of the contexts
    from which the compiler is required to deduce the template arguments".

    > Is there some
    > way to get the compiler to see `f' without having to explicitly
    > specify the template argument type?
    >
    > template<class T>
    > struct A {
    > enum B {
    > };
    > };
    >
    > template<class T>
    > void f(typename A<T>::B a)
    > {
    > }
    >
    > int main ()
    > {
    > A<int>::B a0 = A<int>::B();
    > f(a0); // don't want to explicitly specify f<int>(a0) here
    > }
    >
    > I have been able to move the definition of `f' into A to get the
    > results I want, but I'd like to declare/define the function outside of
    > A if possible. Is there something wrong with my declaration of `f', or
    > is there some other way to do what I want?


    Wrong? You'll have to define "wrong". A member of a template is not a
    deducible context. The reason is rather benign, I think: there can be a
    specialization (or partial, which means virtually unlimited number of
    them) of your 'A' template which has no 'B' member, or a different 'B'
    member, so the compiler would have to look through all specializations
    of 'A' (the set of which is open at the time of compiling 'f(a0)', to
    determine what 'T' is. That's asking too much, and thus the members of
    template are not required to be a deducible context.

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 19, 2012
    #2
    1. Advertising

  3. Travis Vitek

    Travis Vitek Guest

    On Jan 19, 5:12 am, Victor Bazarov <> wrote:
    >
    > Wrong?  You'll have to define "wrong".  A member of a template is nota
    > deducible context.


    Okay, that is what I am doing wrong. I'll have to read the standard to
    find a way around this. That will probably answer my second
    question... what can I do to make my declaration of `f' legal?

    I have the following which appears to work.

    template<class T>
    struct A {
    enum B {
    };

    friend void f(B);
    };

    int main ()
    {
    A<int>::B a0 = A<int>::B();
    f(a0);
    }

    I don't really want to make `f' a friend of A if I don't have to, but
    this is the only way I can see to get the functionality I want. I also
    don't understand how I would define `f' outside of the body of A. I
    realize I could define it in the body as an inline function, and maybe
    that is what I'll have to do. I just want to know if I'm missing
    something that would allow me to be able to define it out of line.

    Travis
     
    Travis Vitek, Jan 19, 2012
    #3
  4. Travis Vitek

    Travis Vitek Guest

    On Jan 19, 7:34 am, Travis Vitek <> wrote:
    >
    > what can I do to make my declaration of `f' legal?
    >


    I suppose I should be a bit more specific. I _need_ to be able to call
    `f' without specifying the template parameter. In my actual code, B is
    a type that I want to be able to use with bitwise operators. More
    succinctly...

    template<class T>
    struct A {
    enum bitfield {
    zero = 0,
    one = 1,
    two = 2,
    four = 4
    };

    friend bitfield operator|(bitfield lhs, bitfield rhs);
    friend bitfield operator&(bitfield lhs, bitfield rhs);
    friend bitfield operator^(bitfield lhs, bitfield rhs);
    friend bitfield operator~(bitfield rhs);

    friend bitfield& operator|=(bitfield& lhs, bitfield rhs);
    friend bitfield& operator&=(bitfield& lhs, bitfield rhs);
    friend bitfield& operator^=(bitfield& lhs, bitfield rhs);
    };

    int main ()
    {
    A<int>::bitfield b = A<int>::eek:ne | A<int>::four;
    }

    Travis
     
    Travis Vitek, Jan 19, 2012
    #4
  5. Re: Difficulty declaring free function that takes parameter thatis a nested member of a class template

    On 1/19/2012 10:34 AM, Travis Vitek wrote:
    > On Jan 19, 5:12 am, Victor Bazarov<> wrote:
    >>
    >> Wrong? You'll have to define "wrong". A member of a template is not a
    >> deducible context.

    >
    > Okay, that is what I am doing wrong. I'll have to read the standard to
    > find a way around this. That will probably answer my second
    > question... what can I do to make my declaration of `f' legal?
    >
    > I have the following which appears to work.
    >
    > template<class T>
    > struct A {
    > enum B {
    > };
    >
    > friend void f(B);
    > };
    >
    > int main ()
    > {
    > A<int>::B a0 = A<int>::B();
    > f(a0);
    > }
    >
    > I don't really want to make `f' a friend of A if I don't have to, but
    > this is the only way I can see to get the functionality I want. I also
    > don't understand how I would define `f' outside of the body of A. I
    > realize I could define it in the body as an inline function, and maybe
    > that is what I'll have to do. I just want to know if I'm missing
    > something that would allow me to be able to define it out of line.


    I am not sure why (or how) declaring a friend function like you did
    above provides you with a solution. I don't see the full code, I can't
    try it to see the result. Is 'f' still a template? Do you get the
    "right" 'f' instantiated in that case? Or do you just get no diagnostic
    from your compiler?

    The Standard actually says nothing about friends versus non-friends AFA
    template argument deduction goes, so there should be no difference
    (although I haven't checked the new Standard yet). Perhaps what you see
    is not exactly what you need...

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 19, 2012
    #5
  6. Re: Difficulty declaring free function that takes parameter thatis a nested member of a class template

    On 1/19/2012 10:46 AM, Travis Vitek wrote:
    > On Jan 19, 7:34 am, Travis Vitek<> wrote:
    >>
    >> what can I do to make my declaration of `f' legal?
    >>

    >
    > I suppose I should be a bit more specific. I _need_ to be able to call
    > `f' without specifying the template parameter. In my actual code, B is
    > a type that I want to be able to use with bitwise operators. More
    > succinctly...
    >
    > template<class T>
    > struct A {
    > enum bitfield {
    > zero = 0,
    > one = 1,
    > two = 2,
    > four = 4
    > };
    >
    > friend bitfield operator|(bitfield lhs, bitfield rhs);
    > friend bitfield operator&(bitfield lhs, bitfield rhs);
    > friend bitfield operator^(bitfield lhs, bitfield rhs);
    > friend bitfield operator~(bitfield rhs);
    >
    > friend bitfield& operator|=(bitfield& lhs, bitfield rhs);
    > friend bitfield& operator&=(bitfield& lhs, bitfield rhs);
    > friend bitfield& operator^=(bitfield& lhs, bitfield rhs);
    > };
    >
    > int main ()
    > {
    > A<int>::bitfield b = A<int>::eek:ne | A<int>::four;
    > }


    Your operator functions have two arguments. Are they supposed to be the
    inner type of the same template? Or is it possible to do

    auto b = A<float>::eek:ne | A<long>::four;

    ?

    In similar situations when I've run into compiler's inability to deduce
    template arguments, and especially when operators are concerned, the
    solution would always be to have a named function, and (yes,
    unfortunately) supply the template argument to it. IOW, something like

    auto b = Op_or<int>(A<int>::eek:ne | A<int>::four);

    You *could* of course have your 'one' and 'four' be of a particular
    user-defined type (not 'enum') and define the operators *as members*.
    In that case the name lookup should work differently and the template
    argument deduction isn't really needed since you've already provided it
    (when you write A<int>::eek:ne, that is).

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 19, 2012
    #6
  7. Travis Vitek

    Travis Vitek Guest

    On Jan 19, 9:52 am, Victor Bazarov <> wrote:
    >
    > I am not sure why (or how) declaring a friend function like you did
    > above provides you with a solution.
    >


    I'm not sure how to respond. Your response makes is sound like you're
    confused about how or why the code works.

    > I don't see the full code, I can't
    > try it to see the result.  Is 'f' still a template?  Do you get the
    > "right" 'f' instantiated in that case?  Or do you just get no diagnostic
    > from your compiler?


    The provided code compiles without diagnostic. If I add
    implementations of each of the operators, they all behave as expected
    and are called when they should be without explicitly specifying any
    template type at the call site. i.e., it works.

    Travis
     
    Travis Vitek, Jan 19, 2012
    #7
  8. Re: Difficulty declaring free function that takes parameter thatis a nested member of a class template

    On 1/19/2012 6:15 PM, Travis Vitek wrote:
    > On Jan 19, 9:52 am, Victor Bazarov<> wrote:
    >>
    >> I am not sure why (or how) declaring a friend function like you did
    >> above provides you with a solution.
    >>

    >
    > I'm not sure how to respond. Your response makes is sound like you're
    > confused about how or why the code works.


    There is no indication in the Standard (or at least I can't find it)
    that placing a declaration of your 'f' function as a friend into that
    class template *should* help the compiler deduce the template argument.
    Do you understand what I am writing here? If your compiler somehow
    deduces the argument from the context beyond the listed in the Standard,
    fine. The compilers are allowed to do that. It's called "a language
    extension". It's not portable. It's not even guaranteed to be valid
    code in the next version of the same compiler.

    I would like to hear from language experts (especially those who deal
    with templates more than I do) about this, but I've not seen anybody
    chime it yet.

    >
    >> I don't see the full code, I can't
    >> try it to see the result. Is 'f' still a template? Do you get the
    >> "right" 'f' instantiated in that case? Or do you just get no diagnostic
    >> from your compiler?

    >
    > The provided code compiles without diagnostic. If I add
    > implementations of each of the operators, they all behave as expected
    > and are called when they should be without explicitly specifying any
    > template type at the call site. i.e., it works.


    Good for you. Problem solved, then?

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jan 20, 2012
    #8
  9. On Jan 20, 6:52 am, Victor Bazarov <> wrote:
    > There is no indication in the Standard (or at least I can't find it)
    > that placing a declaration of your 'f' function as a friend into that
    > class template *should* help the compiler deduce the template argument.
    >   Do you understand what I am writing here?  If your compiler somehow
    > deduces the argument from the context beyond the listed in the Standard,
    > fine.  The compilers are allowed to do that.  It's called "a language
    > extension".  It's not portable.  It's not even guaranteed to be valid
    > code in the next version of the same compiler.
    >
    > I would like to hear from language experts (especially those who deal
    > with templates more than I do) about this, but I've not seen anybody
    > chime it yet.


    If your analysis is right, wouldn't that interfere with function
    resolution and function overloading, and maybe even hide functions?
    That would break and/or change the meaning of well formed programs,
    and that is not allowed as a "language extension".
     
    Joshua Maurice, Jan 20, 2012
    #9
  10. Travis Vitek

    Travis Vitek Guest

    On Jan 20, 6:52 am, Victor Bazarov <> wrote:
    > On 1/19/2012 6:15 PM, Travis Vitek wrote:
    >
    > > On Jan 19, 9:52 am, Victor Bazarov<>  wrote:

    >
    > >> I am not sure why (or how) declaring a friend function like you did
    > >> above provides you with a solution.

    >
    > > I'm not sure how to respond. Your response makes is sound like you're
    > > confused about how or why the code works.

    >
    > There is no indication in the Standard (or at least I can't find it)
    > that placing a declaration of your 'f' function as a friend into that
    > class template *should* help the compiler deduce the template argument.


    Sections [temp.inject] and [basic.lookup.koenig] appear to be closely
    related to this issue.

    >   Do you understand what I am writing here?  If your compiler somehow
    > deduces the argument from the context beyond the listed in the Standard,
    > fine.  The compilers are allowed to do that.  It's called "a language
    > extension".  It's not portable.  It's not even guaranteed to be valid
    > code in the next version of the same compiler.


    I find it hard to believe that all of the compilers I'm testing
    implement the same 'language extension'...

    HP aC++ 6.25
    GNU gcc 3.4.6, 4.1.2, 4.3.4, and 4.4.5
    Microsoft Visual Studio 10 and 11
    Oracle SunPro C++ 5.10
    IBM VisualAge C++ 11.1

    >
    > I would like to hear from language experts (especially those who deal
    > with templates more than I do) about this, but I've not seen anybody
    > chime it yet.


    I'm guessing I'll have to take it over to comp.lang.c++.moderated if I
    want to hear from them.

    >
    > Good for you.  Problem solved, then?


    I suppose. It would still be nice to get some validation as to how/why
    this code works, and how I might define the functions outside the body
    of A.

    Travis
     
    Travis Vitek, Jan 21, 2012
    #10
    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. Newsgroup - Ann
    Replies:
    5
    Views:
    610
    John Carson
    Jul 30, 2003
  2. Replies:
    1
    Views:
    475
    Victor Bazarov
    Jul 20, 2005
  3. Azdo
    Replies:
    2
    Views:
    435
  4. Hicham Mouline
    Replies:
    1
    Views:
    356
    Vladyslav Lazarenko
    Mar 27, 2009
  5. A L
    Replies:
    1
    Views:
    511
    Alf P. Steinbach /Usenet
    Aug 25, 2010
Loading...

Share This Page