1

I have the following templated merge sort program:

#include <iostream>
#include <vector>
#include <string>

// trying to create a default method call
class CInstance {
private:
    std::string str_;
public:
    CInstance(const std::string& str) : str_(str) {}
    bool const  operator>(const CInstance& that){  return (this->str_.size() > that.str_.size());}
};

template<class T>
class CObj {
private:
    T val;
public:
    CObj(const T n) : val(n) {}
    T Get() { return val; }
};

template<class T>
using vcobj = std::vector<CObj<T>>;

template<class T>
void display(vcobj<T>& v) {
    for (auto &i : v) {
        std::cout << i.Get() << " ";
    }
    std::cout << "\n";
}

template<class T>
vcobj<T> Merge(vcobj<T>& lv, vcobj<T>& rv) {
    vcobj<T> ret;
    
    auto lsize = lv.size();
    auto rsize = rv.size();
    unsigned int lpin = 0, 
                 rpin = 0;
                 
    while(lpin < lsize &&  rpin < rsize) {
        if(lv.at(lpin).Get() > rv.at(rpin).Get()) {
            ret.emplace_back(rv.at(rpin).Get());
            rpin++;
        }
        else {
            ret.emplace_back(lv.at(lpin).Get());
            lpin++;
        }
    }
    
    for (auto i=lpin; i<lsize; i++) {
        ret.emplace_back(lv.at(i).Get());
    }
    
    for (auto i=rpin; i<rsize; i++) {
        ret.emplace_back(rv.at(i).Get());
    }
    
    return ret;
}

template<class T>
vcobj<T> Sort(const vcobj<T>& v) {
    vcobj<T> ret;
    
    auto size = v.size();
    if(size == 0) {
        return ret;
    }
    if(size > 1) {
        
        auto mid = size / 2;
        
        vcobj<T> l(v.begin(), v.begin()+mid);
        auto lv = Sort(l);
        
        vcobj<T> r(v.begin()+mid, v.end());
        auto rv = Sort(r);
        
        ret = Merge(lv, rv);
        
    }
    else {
        ret = v;
    }
    
    return ret;
}

int main() {
    {
        vcobj<int> v = {4, 5, 2, 1, 9, 6, 10, 8, 15, 3, 7};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    {
        vcobj<float> v = {0.01, 0.001, 0.002, 0.009, 0.010, 0.0003, 0.00001};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    {
        vcobj<std::string> v = {{"pineapple"}, {"jackfruit"}, {"mango"}, {"apple"}, {"banana"}};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    // causing problem
    {
        vcobj<CInstance> v = {{"pineapple"}, {"jackfruit"}, {"mango"}, {"apple"}, {"banana"}};
        display(v);
        auto sorted = Sort(v);
        display(sorted);
    }
    
    return 0;
}

In all of the above types, I can simply call the object and it extracts the data which looks like calling a default get() method. Is there a way to make objects of class CInstance trigger a methos, when used just alone.

example: I could do something like

CInstance obj;
std::cout << obj;

And that will call a default method in CInstance what every it may be.

kishoredbn
  • 2,007
  • 4
  • 28
  • 47
  • No you can't do that in c++. You can overload/specialize operator << of the stream, but then you would only get default behavior ofr streaming. Closest is probably overloading operator() and using std::cout << obj(); – Pepijn Kramer Sep 03 '21 at 15:53
  • Are you considering `std::cout << obj;` to be an example of `obj` being "used just alone"? Isn't it _being used_ as the right-hand operand to the `<<` operator? – Drew Dormann Sep 03 '21 at 15:53
  • Not sure if I understand you correctly. You want to have the possibility to use `obj` in a `std::cout`? stream so that its content will be shown? Or you want to add a possibility that it is e.g. automatically converted to an `std::string`? – t.niese Sep 03 '21 at 15:54
  • BTW, there is [std::merge](https://en.cppreference.com/w/cpp/algorithm/merge) that does all the work you're trying to do in `Merge`. Also, if you want a templated merge sort program written in modern C++, [see this link](https://stackoverflow.com/questions/24650626/how-to-implement-classic-sorting-algorithms-in-modern-c) – PaulMcKenzie Sep 03 '21 at 16:04
  • I just realized that all it needed was `operator<< `over loading. Like @t.niese answered, I am looking for more sort of `operator const char *() const` in addtion to `operator<< ` – kishoredbn Sep 03 '21 at 16:21

2 Answers2

1

In this exact case, you define an operator<< method like so:

std::ostream & operator<<(std::ostream &stream, const CInstance &obj) {
    ... output obj however you want to the stream. For instance:
    stream << obj.getAge();
    return stream;
}
Joseph Larson
  • 8,530
  • 1
  • 19
  • 36
1

As already mentioned in the other answer you can create your own operator<< function:

std::ostream & operator<<(std::ostream &stream, const CInstance &obj) {
    
    // stream <<  whatever you want to output

    return stream;
}

You could also define a conversion operator. But you should think twice before you use them. They can lead to problems that are not easy to debug, especially when explicit is omitted. You generally should not use those for logging/debugging purposes. If your type represents a string and you use it to allow an easy conversion to an std::string then it might be fine.

#include <iostream>
#include <string>

class CInstance {
    std::string str_ = "test";
public:
    explicit operator const std::string () const { return str_; }
};

int main() {
    CInstance obj;

    std::cout << (std::string)obj << std::endl;
    return 0;
}

If you can guarantee that the lifetime of the returned const char * is still valid after the call you could also do something like (but I would avoid that solution):

#include <iostream>
#include <string>

class CInstance {
    std::string str_ = "test";
public:
    operator const char *() const   { return str_.c_str(); }
};

int main() {
    CInstance t;

    std::cout << t << std::endl;
    return 0;
}

Personally, I would go with the first solution. But that really depends if you actually have a string representation of CInstance or if you want to display something for debugging purposes in a different format. I however would avoid the last non-explicit version with the const char * conversion operator.

t.niese
  • 39,256
  • 9
  • 74
  • 101
  • awesome tricks. I haven't thought throw overloading `operator<<` for which I asked this question, but some of these solution are great things to implement in code. Thanks for sharing that. – kishoredbn Sep 03 '21 at 16:19
  • 1
    @kishoredbn you really should think about whether or not you want to use those conversion operators. These can lead to hard to debug problems with the code, especially if you omit the `explicit`. So you should really think about if it is worth using them. – t.niese Sep 03 '21 at 16:21