Template class to call some function of other classes based on their presence and priority and more type restrictions like const and case sensitivity

user5697768

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", "[email protected]" };
    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
skypjack

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", "[email protected]" };
    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;
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Can not call a function to a class from other classes

Call function based on template argument type

Return type of function call on template argument class

Template class char*, return type of function const char*?

Trying to overload a virtual function in a template class based on template type

Type of class based on template type

Multiple restrictions on generic type based on super and sub classes in java

Case sensitivity of Java class names

Add Case Sensitivity to CountIf function

forcing argument and return type restrictions on a function based on it's parameterized types

Call a member function of other Class

How to call other class' const member function via a std::unique_ptr member

Class template based wrapping function

Typescript: Declaring a function signature type like const

template template class, call a function if it exists

Expression SFINAE: how to select template version based on whether type contains a function with one or more arguments

How to call a function with some return type from function of Main class in Java?

How to realize template class type in template function?

Function with template and Priority Queue

Weird case sensitivity bug in Class.getResource?

How to use some class in paramater template other class?

BigQuery Domain Function Case Sensitivity Discrepancy

Call variadic function template with template parameters of variadic class template?

Passing a function of a class as argument to call it on a list of classes

Select member type of class template based on template type?

Change class members types based on template type, but not to the template type

Cannot use some type in function call

Case SQL query based on priority

Function template argument deduction with variadic class template as function call parameter