Operator overloading for an inner class of a class template causes compilation error

This is a discussion on Operator overloading for an inner class of a class template causes compilation error within the C++ Programming forums, part of the General Programming Boards category; Hi, could you please answer why the following code causes a compilation error? How could one avoid the error while ...

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    3

    Operator overloading for an inner class of a class template causes compilation error

    Hi,

    could you please answer why the following code causes a compilation error?
    How could one avoid the error while keeping the definition of the struct B within the struct A?

    Code:
    #include <iostream>
    
    template<typename T> struct A {
       struct B { T t; };
       B b;
    };
    
    template<typename T>
    std::ostream& operator << (std::ostream& os, const typename A<T>::B& b) {
        return os<<"an instance of B";
    }
    
    int main() {
        A<int> a;
        std::cout<<a.b<<std::endl;
        return 0;
    }
    It seems to me that for some reason the compiler can't deduce the type needed. I unsuccessfully tried to compile the code using MS VC++ 2005 compiler and Borland C++ Compiler 5.5.

    MS VC++ 2005 compiler says:
    binary '<<' : no operator found which takes a right-hand operand of type 'A<T>::B' (or there is no acceptable conversion) with [T=int]

    Borland C++ Compiler 5.5 says:
    'operator<<' not implemented in type 'std::ostream' for arguments of type 'A<int>::B' in function main()

    Thanks!
    Alex

  2. #2
    C++まいる!Cをこわせ! Elysia's Avatar
    Join Date
    Oct 2007
    Posts
    22,456
    Maybe

    Code:
    template<typename T>
    std::ostream& A<T>::B::operator << (std::ostream& os, const typename A<T>::B& b) {
        return os<<"an instance of B";
    }
    ?
    Last edited by Elysia; 11-09-2007 at 02:41 PM.

  3. #3
    Registered User
    Join Date
    Nov 2007
    Posts
    3
    Thank you for your answer.
    However it can't help me since the operator must not be a member of the struct B
    (the operator takes ostream as the left operand).

    Alex

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,652
    That's an interresting problem. I couldn't get GCC to understand what you're trying to do without making it a friend function....
    Code:
    template<typename T> 
    struct A 
    {
        struct B 
        {
            T t; 
        };
        
        B b;
    
        friend std::ostream& operator << (std::ostream& os, const B &b) 
        {
            return os << "an instance of B";
        }
    };
    gg

  5. #5
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,237
    I'm not exactly sure why the compiler is unable to infer the proper type here. There is a workaround. Instead of specifying "typename A<T>::B&" as the type, just use "T&".

    But you say, "This will cause the operator to be invoked for EVERY type T, not just those of form A<X>::B." Correct. So we need to use some template instantiation rules to prevent that from happening. In this case, SFINAE, "Specialization failure is not an error."

    You can do this by adding a special member to the B structure which indicates that it is, in fact, of type A<X>::B. Let's make a bogus class called I_Am_A_B:

    Code:
    struct I_Am_A_B { };
    Then place an instance of this class inside the B struct:

    Code:
    template <typename T>
    struct A
    {
        struct B { T t; I_Am_A_B i_am_a_b; }
        B b;
    };
    
    template <typename T>
    std::ostream& operator<<(std::ostream& os, const T& b)
    {
        return os<<"an instance of B";
        // PREVENT INSTANTIATION OF THIS TEMPLATE IF T IS NOT A A<X>::B TYPE.
        b.i_am_a_b;
    }
    Does that look awful? That's because it is. But it's the only way I could make it work (aside from the friend method someone else found).

  6. #6
    Registered User
    Join Date
    Nov 2007
    Posts
    3
    Dear Codeplug and brewbuck,

    thank you for your answers!
    I believe both pieces of code you provided (and even my code) must be compilable with a "right" compiler. Unfortunately, this is not the case for MS VC++ 2005 compiler and Borland C++ Compiler 5.5. According to Codeplug's message, GCC is more "right".

    brewbuck, do you know a compiler that compiles the code you provided?

    Thanks!
    Alex

  7. #7
    Captain Crash brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,237
    Quote Originally Posted by cale View Post
    Dear Codeplug and brewbuck,

    thank you for your answers!
    I believe both pieces of code you provided (and even my code) must be compilable with a "right" compiler. Unfortunately, this is not the case for MS VC++ 2005 compiler and Borland C++ Compiler 5.5. According to Codeplug's message, GCC is more "right".
    My gcc didn't compile your code, either.

    brewbuck, do you know a compiler that compiles the code you provided?
    I tested it on gcc. Seems to work here. Good luck. I wish I knew why the original doesn't work.

  8. #8
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    The compiler cannot infer the template parameter T for your case. There was a thread here not long ago ...
    Metaprogramming Issue

    I believe Codeplug's version, if it works, would be best. brewbuck's version works, too, but comes with size overhead in B. That can be changed by making B::ImaB a type, not a member, and using MPL's HAS_XXX and Boost.EnableIf.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Getting other processes class names
    By Hawkin in forum Windows Programming
    Replies: 3
    Last Post: 03-20-2008, 04:02 PM
  3. How to monitor process creation?
    By markiz in forum Windows Programming
    Replies: 31
    Last Post: 03-17-2008, 02:39 PM
  4. Crazy errors caused by class, never seen before..
    By Shamino in forum C++ Programming
    Replies: 2
    Last Post: 06-10-2007, 11:54 AM
  5. load gif into program
    By willc0de4food in forum Windows Programming
    Replies: 14
    Last Post: 01-11-2006, 09:43 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21