#include <iostream>
// File: koenig.cpp by Erich Kaltofen, March 25, 2026
// ------------------------
// The program analyzes the C++ version
//
//    std::cout << "Hello world!" << std::endl;
//
// of the Kernighan-Ritchie C statement
//
//    printf("Hello world!\n);
//
// Both << operators are compiled with argument dependent lookup (ADL)
// ------------------------

// We first give the standard ADL (Koenig) lookup example
namespace bar {
class dummy_t {}; // empty encapsulated class for ADL
void foo(dummy_t T, int i) {std::cout << "bar::foo call: " << i << std::endl;}
}// namespace bar

// the template function expansion for std::endl from <ostream> for cout;
// the code not needed, but explains the std::endl output manipulator function
template
    std::basic_ostream<char, std::char_traits<char> >&
    std::endl(std::basic_ostream<char, std::char_traits<char> >& os);

// program is without "using namespace std;" to exercise ADL

int main(void) {

    foo(bar::dummy_t(), 5); // standard argument-dependent lookup example:
               // bar::foo() is called because one argument is in the scope bar::

    std::cout << "1. Hello world!" // ADL for std::operator<< because
                                   // first argument is in namespace std 
                                   // compiles to std::operator<< function
                                   // see 2. below
              << std::endl; // ADL for std::operator<<
                            // compiles to basic_ostream<...>::operator<<
                            // template member operator
                            // see 5.-7. below
    // note: std:endl is a function which is run (see 3.-5. below)

    // what calls the compiler generates
    operator<<(std::cout, "2. Hello world!");
    // Note: 1. ADL of operator<< because an argument is in namespace std.
    //          std::operator<< is defined for second argument type const char[]
    //       2. there is a second possible match with the
    //          templated basic_stream<...>::operator<< (void* T); see 7. below.
    //
    //          The template function for std::operator<<, namely,
    //
    //  template<typename _CharT, typename _Traits>
    //  inline basic_ostream<_CharT, _Traits>&
    //    operator<<(basic_ostream<_CharT, _Traits>& __out, const _CharT* __s)
    //
    //          is used because the argument type const char* is more specialized
    //          (template specialization for template function operator<<)
    //          Compare with 6. below

    std::cout.operator<<(std::endl); // explicit call with endl function pointer
    // this is to what  std::cout << std::endl;  compiles.  There is no definition
    // for the template function std::operator<< with a second argument type a
    // pointer to a function, std::endl, but there is one for the
    // template member function
    //
    //  __ostream_type&
    //  basic_ostream<...>::operator<<(ios_base& (*__pf) (ios_base&))
    //     { __pf(*this); return *this; }


    // call with fully scoped and template expanded endl function
    std::operator<<(std::cout, "3. Hello world!");
    std::cout.operator<<(std::endl<char, std::char_traits<char> >);

    // using endl as a function 
    std::cout << "4. Hello world!";
    endl(std::cout); // explicit call to std::endl template function
                     // ADL look-up: no function endl in global scope
                     // But there is a template function in namespace std

    std::cout << std::basic_string<char>("5. Hello world!");
    // note: cannot do  std::cout.operator<<(std::basic_string<char>("Hello"));
    // because argument type is not defined in member operator
    std::cout.operator<<(std::endl); // explicit call with endl function pointer

    std::cout << "doing std::cout.operator<<(\"6. Hello world!\") ";
    std::cout.operator<<("6. Hello world!"); // prints pointer address
    // template operator<< member operator has pointer argument type
    //
    // __ostream_type& basic_ostream<...>::operator<<(const void* __p)
    //     { return _M_insert(__p); }
    //
    // and then prints the pointer in hexadecimal.
    std::endl(std::cout); // fully scoped call

    return 0;
}// main
