模板类根据其存在和优先级以及更多类型限制(如const和区分大小写)调用其他类的某些函数

时间:2017-01-07 06:16:24

标签: c++ oop c++11 templates operator-overloading

我有这样的结构/类:

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; 
    }
}; 

我正在创建一个模板PPrint类,如果它存在,它将调用该类的pPrint函数。如果没有,它将调用该类的toString函数,如果它也不可用,它将打印 NO print function

优先级:

  1. 调用pPrint
  2. 调用toString
  3. 只需输出无打印功能
  4. 我的主要职能:

    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; 
    }
    

    现在我创建了这个类,如下所示:

    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";
        }
    
    };
    

    它不正确,因为它不能区分const及其给出的错误,如下所示我的编译器,但在其他人上运行并打印H的功能(它必须不打印):

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

    但它在意识形态和Coliru上运行良好。

    我应该如何创建此类或删除此类错误? 主要挑战是:

    1. Prioriy(前面提到过)
    2. 区分大小写的相同功能
    3. Const类型区分函数应该只有pPrint和const也是。
    4. 你不能解决任何结构和主要功能中的模板类应该是单独的和独立的。
    5. 仅限C ++ 11标准
    6. 该课程仅适用于这两个原型:

      1. ostream& pPrint(ostream& ost) const // case sentive for pPrint
      2. std::string toString() const
      3. 参考文献:

        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

1 个答案:

答案 0 :(得分:1)

您可以使用类似的方法来减少解决方案的样板并解决问题:

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);
}

重载,继承和sfinae将完成这项工作。

基于问题代码的最小工作示例:

#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;
}