我有这样的结构/类:

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”

优先 :-
1)p打印
2)toString
3)仅输出“无打印功能”
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;
}

现在我已经创建了这个类,如下所示:
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;
}

但它不起作用
引用:Check if a class has a member function of a given signature

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

应该检测到带有该原型(prototype)的pPrint:
ostream& pPrint(ostream& ost) const;

但结构中的功能可能类似于:(不应被检测到)
ostream& PPrint(ostream& ost) const; // case sensitive and same name as class name
ostream& pPrint(ostream& ost);  //without const specifier

如何构造Template Class PPrint来做到这一点?

最佳答案

我认为更好的方法是通过在C++ 17中标准化为std::is_detected的检测习惯用法
C++ 11
首先,我们需要一些辅助结构和类型别名来实现检测习惯用法:

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;
然后,我们简化了tag-dispatch调用:
 pPrint(T m)
 {
     CallPrint(m, HaspPrintMethod_t<T>());
 }
如果没有pPrint方法可用,我们将输入std::false_type标记,然后将其进一步调度:
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
我们的测试:
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;
输出:

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

C++ 17
我们的检测习惯用法将使用std::is_detectedconstexpr if
Demo
(我认为编译器尚不支持[[maybe_unused]] attribute specifier,否则我将使用它并挤压该警告)
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";
        }
    }
}

关于c++ - 模板类根据其存在和优先级调用其他类的某些命名函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/41488450/

10-10 22:16
查看更多