0

I have structs/classes like these:

struct LD {                             //Login detail
        std::string username;
        std::string password;

        std::string toString() const {
        return "Username: " + username
    + " Password: " + password;
    }
};

struct UP {                          //User Profile
    std::string name;
    std::string email;

    ostream& pPrint(ostream& ost) const {
        ost << "Name: " << name
        << " Email: " << email;
        return ost;
    }

std::string toString() const {
    return "NULLSTRING";
    }
};

struct CD {       //ContactDetails
    std::string m_phoneNumber; 
    std::string m_address; 
    ostream& pPrint(ostream& ost) { //NO CONST must not print
        ost << "PhoneNumber: " << m_phoneNumber << " Address:" << m_address;
        return ost; 
    } 
} ; 

struct H { 
    std::string hobbies;
    ostream& PPrint(ostream& ost) {  //its not case equivalent and not const so it should not be called
        ost << "Hobbies: " << m_hobbies; 
        return ost; 
    } 
} ; 

struct PD { 
    std::string cardNumber; 
    ostream& pPrint(ostream& ost) const {
        ost << "CardNumber: " << m_cardNumber;
        return ost; 
    } 
} ; 

struct BN { 
    std::string m_bankName; 
    std::string toString() const {
        return "BANKNAME"; 
        } 

    ostream& simplePrint(ostream& ost) const {
        ost << "BankName: " << m_bankName;
        return ost; 
    }
} ; 

struct DI { 
    std::string toString() const { 
        return "i0S"; 
        } 

    ostream& pPrint(ostream& ost) const {
        ost << "Android: JellyBean";
        return ost; 
    }
}; 

I am creating a template PPrint class which will call pPrint function of that class if its present. If not, it will call toString function of that class if its also not available it will print NO print function.

Priorities:

  1. Invoke pPrint
  2. Invoke toString
  3. Simply output NO print Function

My main function:

int main() {
    LD ld = { "And", "Ap" };
    UP  up = { "James Brannd", "jamens@goo.com" };
    CD cd = { "+9198799911", "355 B. Bway, NY" };
    H hb = { "sing, dance, read"}; 
    PD pd = { "444411113336667732222" }; 
    BN bn = { "SBI" }; 
    DI di; 

    std::cout << PPrint <UP> (up) << std::endl;
    std::cout << PPrint <LD> (ld) << std::endl;
    std::cout << PPrint <CD> (cd) << std::endl;
    std::cout << PPrint <H>(hb) << std::endl;
    std::cout << PPrint <PD> (pd) << std::endl; 
    std::cout << PPrint <BN> (bn) << std::endl;
    std::cout << PPrint <DI> (di) << std::endl; 
}

Now I have created this class as below:

template<class...>
using void_t = void;

// pPrint
template<typename T, typename = void_t<>>
struct HaspPrintMethod : std::false_type{};

template<typename T>
struct HaspPrintMethod<T, void_t<decltype(std::declval<T>  ().pPrint(std::declval<std::ostream&>()))>> : std::true_type{};

// PPrint
template<typename T, typename = void_t<>>
struct HasPPrintMethod : std::false_type{};

template<typename T>
struct HasPPrintMethod<T, void_t<decltype(std::declval<T>().PPrint(std::declval<std::ostream&>()))>> : std::true_type{};

template<typename T>
using HasPPrintMethod_t = typename HasPPrintMethod<T>::type;

// both pPrint and PPrint
template<typename T>
struct HasAnyPPrintMethod : std::integral_constant<bool,    HasPPrintMethod<T>::value || HaspPrintMethod<T>::value>{};

template<typename T>
using HasAnyPPrintMethod_t = typename HasAnyPPrintMethod<T>::type;

template<typename T, typename=void_t<>>
struct HastoStringMethod : std::false_type{};

template<typename T>
struct HastoStringMethod<T, void_t<decltype(std::declval<T>().toString())>> : std::true_type{};

template<typename T>
using HastoStringMethod_t = typename HastoStringMethod<T>::type;

template <class T>
class PPrint {
    public:
    PrettyPrint(T m)
    {
        CallPrint(m, HasAnyPPrintMethod_t<T>());
    }

    std::string buf;

    private:
    void CallPrint( T& m, std::true_type)
    {
        CallPPrint(m, HasPPrintMethod_t<T>());

    }

    void CallPPrint(T& m, std::true_type)
    {
        std::ostringstream  os;
        m.PPrint(os); //need correction as pPrint is only priority for THis "NO print function" if pPrint is nor there and toString is not there I mean it should ignored
        buf = os.str();
    }

    void CallPrettyPrint(T& m, std::false_type)
    {
        std::ostringstream  os;
        m.pPrint(os);  //only i want this one as 1st priority PPrint must be not used anywhere , should not be printed
        buf = os.str();
    }

    void CallPrint( T& m, std::false_type)
    {
        CallPrintNoPPrint(m, HastoStringMethod_t<T>());
    }

    void CallPrintNoPPrint( T& m, std::true_type)
    {
        buf = m.toString();
    }
    void CallPrintNoPrettyPrint( T& m, std::false_type)
    {
        buf = "NO print Function";
    }

};

It's not correct because it's not distinguishing for const and its giving error like below for my compiler but running on others and printing H's function (which it must not print):

error: ‘struct UP’ has no member named ‘PPrint’
         m.PrettyPrint(os); 

But it's running fine on ideone and Coliru.

How should I create such class or remove such errors?
Main challenges are:

  1. Prioriy (mentioned earlier)
  2. Case sensitive same function
  3. Const type distinguish function should be pPrint only and const too.
  4. You cant what's inside any of the struct and main function that is template class should be seperate and independent.
  5. Only C++11 standards

The class should work for this two prototype only:

  1. ostream& pPrint(ostream& ost) const // case sentive for pPrint
  2. std::string toString() const

References:

  1. Template class to call some named function of other classes based on their presence and priority
  2. Check if a class has a member function of a given signature
Community
  • 1
  • 1

1 Answers1

1

You can use something like this to reduce the boilerplate of your solution and solve the issue:

struct SimplyOutput {};
struct ToString: SimplyOutput {};
struct PPrint: ToString {};

template<typename T>
void pPrintImpl(SimplyOutput, const T &) {
    // Do whatever you want here
}

template<typename T>
auto pPrintImpl(ToString, const T &t)
-> decltype(t.toString()) {
    // Do whatever you want here
}

template<typename T>
auto pPrintImpl(PPrint, const T &t)
-> decltype(t.pPrint(std::declval<std::ostream>())) {
    // Do whatever you want here
}

template<typename T>
auto pPrint(const T &t)
-> decltype(pPrintImpl(PPrint{}, t)) {
    return pPrintImpl(PPrint{}, t);
}

Overloading, inheritance and sfinae will do the job.


Below a minimal, working example based on the code in the question:

#include<iostream>
#include<string>
#include<sstream>

struct LD {                             //Login detail
        std::string username;
        std::string password;

        std::string toString() const {
        return "Username: " + username
    + " Password: " + password;
    }
};

struct UP {                          //User Profile
    std::string name;
    std::string email;

    std::ostream& pPrint(std::ostream& ost) const {
        ost << "Name: " << name
        << " Email: " << email;
        return ost;
    }

std::string toString() const {
    return "NULLSTRING";
    }
};

struct CD {       //ContactDetails
    std::string m_phoneNumber; 
    std::string m_address; 
    std::ostream& pPrint(std::ostream& ost) { //NO CONST must not print
        ost << "PhoneNumber: " << m_phoneNumber << " Address:" << m_address;
        return ost; 
    } 
} ; 


struct H { 
    std::string m_hobbies;
    std::ostream& PPrint(std::ostream& ost) {  //its not case equivalent and not const so it should not be called
        ost << "Hobbies: " << m_hobbies; 
        return ost; 
    } 
} ; 

struct PD { 
    std::string m_cardNumber; 
    std::ostream& pPrint(std::ostream& ost) const {
        ost << "CardNumber: " << m_cardNumber;
        return ost; 
    } 
} ; 

struct BN { 
    std::string m_bankName; 
    std::string toString() const {
        return "BANKNAME"; 
        } 

    std::ostream& simplePrint(std::ostream& ost) const {
        ost << "BankName: " << m_bankName;
        return ost; 
    }
} ; 

struct DI { 
    std::string toString() const { 
        return "i0S"; 
        } 

    std::ostream& pPrint(std::ostream& ost) const {
        ost << "Android: JellyBean";
        return ost; 
    }
};

template<typename T>
class PPrint {
    struct SimplyOutputTag {};
    struct ToStringTag: SimplyOutputTag {};
    struct PPrintTag: ToStringTag {};

    template<typename U = T>
    void internal(SimplyOutputTag, const U &) {
        buf = "NO print Function";
    }

    template<typename U = T>
    auto internal(ToStringTag, const U &u)
    -> decltype(u.toString(), void()) {
        buf = u.toString();
    }

    template<typename U = T>
    auto internal(PPrintTag, const U &u)
    -> decltype(u.pPrint(std::declval<std::ostringstream &>()), void()) {
        std::ostringstream os;
        u.pPrint(os);
        buf = os.str();
    }

public:
    PPrint(const T &t) {
        internal(PPrintTag{}, t);
    }

    std::string get() const { return buf; }

private:
    std::string buf;
};

template<typename T>
std::ostream & operator << (std::ostream &os, const PPrint<T> &pp) {
    os << pp.get();
    return os;
}

int main() {
    LD ld = { "And", "Ap" };
    UP  up = { "James Brannd", "jamens@goo.com" };
    CD cd = { "+9198799911", "355 B. Bway, NY" };
    H hb = { "sing, dance, read"}; 
    PD pd = { "444411113336667732222" }; 
    BN bn = { "SBI" }; 
    DI di; 

    std::cout << PPrint <UP> (up) << std::endl;
    std::cout << PPrint <LD> (ld) << std::endl;
    std::cout << PPrint <CD> (cd) << std::endl;
    std::cout << PPrint <H>(hb) << std::endl;
    std::cout << PPrint <PD> (pd) << std::endl; 
    std::cout << PPrint <BN> (bn) << std::endl;
    std::cout << PPrint <DI> (di) << std::endl;
}
skypjack
  • 49,335
  • 19
  • 95
  • 187
  • any demo? Skypjack –  Jan 07 '17 at 10:10
  • @VenuKantSahu Simply use this instead of your stuff. It should work _as is_, more or less. – skypjack Jan 07 '17 at 10:39
  • I am not familiar with this type of style, so i will require a demo or any good place to learn this? @skypjack –  Jan 07 '17 at 11:50
  • PPrint should be a template class first of all to this as I can't change whats inside main or what's inside struct. –  Jan 07 '17 at 11:58
  • @VenuKantSahu Added a minimal, working example based on your code. See [here](http://coliru.stacked-crooked.com/a/a77e2b14a4b4b27d) or the answer above. – skypjack Jan 08 '17 at 09:54