#include <iostream>
#include <iomanip>

//---------------------------------------------------------

class Logger {
  public:
    void write(int x);
    void write(double x);
    
    template <typename T>
    void writeLine(T x);
};

void Logger::write(int x) {
    std::cout << x;
}

void Logger::write(double x) {
    std::cout << std::setprecision(3) << x;
}

template <typename T>
void Logger::writeLine(T x) {
    write(x);
    std::cout << std::endl;
}

//---------------------------------------------------------

class FooType1 {};
class FooType2 {};

class FooLogger : public Logger {
  public:
    using Logger::write;
    
    void write(FooType1 x);
    void write(FooType2 x);
};


void FooLogger::write(FooType1 x) {
    std::cout << "<value of type FooType1>";
}
void FooLogger::write(FooType2 x) {
    std::cout << "<value of type FooType2>";
}

//---------------------------------------------------------

int main(int argc, char **argv) {
    FooLogger log;
    FooType1 foo1;
    FooType2 foo2;
    
    log.write(42);           // OK
    log.write(3.14159);      // OK
    log.write(foo1);         // OK
    log.write(foo2);         // OK
    
    std::cout << std::endl;
    
    log.writeLine(42);       // OK
    log.writeLine(3.14159);  // OK
    // log.writeLine(foo1);     // error: no matching member function for call to 'write'
    // log.writeLine(foo2);     // error: no matching member function for call to 'write'
}
