模板类根据其存在和优先级来调用其他类的某些命名函数 [英] Template class to call some named function of other classes based on their presence and priority

查看:68
本文介绍了模板类根据其存在和优先级来调用其他类的某些命名函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的结构/类:

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

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

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"

优先级:- 1)p打印 2)toString 3)仅输出无打印功能"

priority :- 1)pPrint 2)toString 3)simply output "NO print Function"

int main() {

    LD ld = { "And", "Ap" };
    UP  up = { "James Brannd", "jamens@goo.com" };

    // this should print "Name: James Email: jamens@goo.com"
    std::cout << PPrint <UP> (up) << std::endl;

    // this should print "Username: And Password: Ap"
    std::cout << PPrint <LD> (ld) << std::endl;
}

现在我已经按照如下方法创建了此类:

now I have created this class as below:

template<typename T>
struct HaspPrintMethod
{
    template<typename U, std::ostream&(U::*)(std::ostream&) const> struct     SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::pPrint>*);
    template<typename U> static int Test(...);
    static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template <class T>
class PPrint {
    public:
    PPrint(T m)
    {
        CallPrint(m, std::integral_constant<bool,     HaspPrintMethod<T>::Has>());
    }
    void CallPrint(const T& m, std::true_type)
    {
        std::ostringstream  os;
        m.pPrint(os);
        buf = os.str();
    }
    void CallPrint(const T& m, std::false_type)
    {
        buf = m.toString();
    }
    std::string buf;
};
template <class T>
std::ostream& operator<<(std::ostream &os, pPrint<T> const &m)
{
    return os << m.buf;
}

但是它不起作用 请参阅:检查某个类是否具有给定签名的成员函数

but it's not working refer: Check if a class has a member function of a given signature

新要求: 模板类名称为PPrint 我们要检测的功能是 1)pPrint 2)toString 3)如果不是,请改为无可用功能"

new requirement:- Template Class name is PPrint the function we want to detect is 1)pPrint 2)toString 3)if not this to "No func available"

具有此原型的pPrint应该被检测到:

pPrint with this prototype should be detected:

ostream& pPrint(ostream& ost) const;

但结构中的函数可以像:(不应被检测到)

but the functions in the structs can be like: (which should not get detected)

ostream& PPrint(ostream& ost) const; // case sensitive and same name as class name
ostream& pPrint(ostream& ost);  //without const specifier 

如何构造模板类PPrint来做到这一点?

How to construct Template Class PPrint to do so?

推荐答案

我认为解决此问题的更好方法是通过在C ++ 17中将检测惯用法标准化为

I think the better way to approach this is via the detection idiom that is being standardized in C++17 as std::is_detected

首先,我们需要一些帮助程序结构和类型别名以实现检测习惯用法:

First we need some helper structs and type aliases to implement the detection idiom:

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

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;

,并检查toString:

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;

然后我们简化标记调度的调用:

And then we simplify the tag-dispatch call:

 pPrint(T m)
 {
     CallPrint(m, HaspPrintMethod_t<T>());
 }

如果没有pPrint方法可用,我们将输入std::false_type标记,然后将其进一步分派:

If no pPrint method is available, we'll enter the std::false_type tag, which we then further dispatch:

void CallPrint(const T& m, std::false_type)
{
    CallPrintNopPrint(m, HasToStringMethod_t<T>());
}

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

实时演示

我们的测试:

Live Demo

Our test:

LD ld = { "And", "Ap" };
UP  up = { "James Brannd", "jamens@goo.com" };

// this should print "Name: James Email: jamens@goo.com"
std::cout << pPrint <UP> (up) << std::endl;

// this should print "Username: And Password: Ap"
std::cout << pPrint <LD> (ld) << std::endl;

// this should print "NO print Function";
struct Foo{};
Foo f;
std::cout << pPrint<Foo>(f) << std::endl;

输出:

姓名:James Brannd电子邮件:jamens@goo.com
用户名和密码:Ap
没有打印功能

Name: James Brannd Email: jamens@goo.com
Username: And Password: Ap
NO print Function

(实际上,我可能会将所有CallPrint方法隐藏为private,因为我不希望用户调用它们,但是我将现有的方法原样保留了,因为这就是OP拥有它们的方式)

(In fact, I'd probably hide all the CallPrint methods as private because I don't expect the user to call them, but I left the existing ones as-is because that's how OP had them)

我们的检测习惯用法将使用 std :: is_detected constexpr if

Our detection idiom will use std::is_detected and constexpr if

(我认为编译器不支持[[maybe_unused]] 属性说明符但是,否则我会用它并挤压该警告)

(I don't think the compiler supports the [[maybe_unused]] attribute specifier yet, else I'd use it and squash that warning)

template<class T>
using HasPrintMethod = decltype(std::declval<T>().pPrint(std::declval<std::ostream&>()));
template<class T>
using HasToStringMethod = decltype(std::declval<T>().toString());

 // ...
constexpr pPrint(T m)
{
    if constexpr(is_detected<HasPrintMethod, T>::value)
    {
        std::ostringstream  os;
        m.pPrint(os);
        buf = os.str();
    }
    else
    { 
        if constexpr (is_detected<HasToStringMethod, T>::value)
        {
           buf = m.toString();
        }
        else
        {
           buf = "NO print Function";
        }
    }
}

这篇关于模板类根据其存在和优先级来调用其他类的某些命名函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆