0

I want to ask two questions here:

  1. To make a generic print function which is capable of printing an array(or vector) of any datatype (eg. int, char, string etc.)
  2. To make a print function which takes input an array(or vector) of objects of a class and invokes the print function (already present in class definition) of that class to print contents of each object.

I was asked this question in placement interview for Zillingo. The interviewer first asked me question 1 but after a very bad attempt of mine, he further complicated it and asked question 2.

The solution I gave for question 1 was that I would make a Print class that has several functions by the name print but each takes an array of different datatype as an argument(one function for every existing datatype). I was completely blank after that.:(

prakasht
  • 448
  • 4
  • 16
  • Why do you think you would need to create a `Print` class that prints other things? Rather than a function - or set of functions - that prints things? Printing is an action, and an action does not need to be represented as an object. – Peter Dec 26 '18 at 10:43
  • 1
    Not trying to be rude, but if templates didn't immediately come to mind when asked this question then, before applying for another C++ job, I recommend reading a good book to get a better grasp on some of the basics of the language. Here's a list: https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list – Lightness Races in Orbit Dec 28 '18 at 15:53
  • @LightnessRacesinOrbit Thanks a lot! I was actually planning to do some online programming courses in the next six months to strengthen my concepts. But I feel lost in the vast number of options.:( – prakasht Jan 01 '19 at 12:08

2 Answers2

2

You can use template function as,

#include <iostream>
#include <vector>
using namespace std;

template <class InputIterator>
void print(InputIterator start,InputIterator end)
{
    for(auto itr=start;itr!=end;++itr)
    {
        cout<<*itr<<" ";
    }
    cout<<endl;
}

int main() {
    int arr[]={1,2,3,4,5};
    print(std::begin(arr),std::end(arr));
    vector<int> in={1,2,6,7};
    print(in.begin(),in.end());
    return 0;
}
user1438832
  • 493
  • 3
  • 10
1

For 1, it looks like:

namespace printing {
  template<class T>
  void print(std::ostream& os, T const& t){
    os<<t;
  }
  template<class It>
  void print_range( std::ostream& os, It b, It e );

  template<class T,std::size_t N>
  void print( std::ostream& os, T const(&arr)[N] ){
    print_range(os, std::begin(arr), std::end(arr) );
  }

  template<class T,std::size_t N>
  void print( std::ostream& os, std::array<T, N> const& arr ){
    print_range(os, std::begin(arr), std::end(arr) );
  }
  template<class T, class A>
  void print( std::ostream& os, std::vector<T, A> const& arr ){
    print_range(os, std::begin(arr), std::end(arr) );
  }
  // etc

  template<class It>
  void print_range( std::ostream& os, It b, It e ){
    for(auto it=b; it!=e; ++it)
      print(os, *it);
  }
}

now, to improve you add SFINAE detection of iterability instead of individual overloads.

For 2, write SFINAE detection of a .print(std::ostream&) method for both pointer and instance types (via decltype and -> and .). Then write print overload that only works for ->print and .print-able types, and have it be a better match than the os<<t; version, but worse than any print free function in the type's namespace.

Doing it right takes a few dozen lines of boilerplate, and I'd want to test the overload order a few times in an actual compiler. In the end os<<t function probably won't be called print or won't be in non-detail namespace.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524