C ++ 11对基类的模板参数包(如果存在)调用成员函数 [英] C++11 call member function on template parameter pack of base classes if present

查看:154
本文介绍了C ++ 11对基类的模板参数包(如果存在)调用成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我查过类似的问题。这是接近,但不是重复。

I have checked questions that are similar. This is close, but not a duplicate.

实质上,我想在基类的参数包(如果存在)上调用函数。我有一个C ++ 11的方式,这样做的工作,但它不会让我感到满意。

In essence I want to call a function on a parameter pack of base classes if present. I have a C++11 way of doing this that works, but it does not feel satisfactory to me.

有人可以提供更好的[更好的性能和更少的样板代码]:

Can someone offer a better [i.e. better performance and less boilerplate code]:

源代码:

#include <iostream>
#include <type_traits>

using namespace std;

// a class initialised with an int that can't do it
struct A
{
    A(int a) : _a(a) {  }
    void report() const { std::cout << _a << std::endl; }
private:
    int _a;
};

// a class initialised with a string that can do it
struct B
{
    B(std::string s) : _b (move(s)) {  }
    void report() const { std::cout << _b << std::endl; }
    void do_it() { std::cout << "B did it with " << _b <<"!" << std::endl; }
private:
    string _b;
};

// a class initialised with an int that can do it
struct D
{
    D(int d) : _d(d) {  }
    void report() const { std::cout << _d << std::endl; }
    void do_it() { std::cout << "D did it with " << _d <<"!" << std::endl; }
private:
    int _d;
};

// a class initialised with a string that can't do it
struct E
{
    E(std::string s) : _e(move(s)) { }
    void report() const { std::cout << _e << std::endl; }
private:
    string _e;
};

// a function enabled only if T::do_it is a member function pointer
// the bool is there just to make this function more attractive to the compiler
// than the next one, below
template<class T>
auto do_it(T& t, bool)
-> typename std::enable_if<std::is_member_function_pointer<decltype(&T::do_it)>::value, void>::type
{
    t.do_it();
}

// a catch-all function called when do_it<T> is not valid
// the ... is less attractive to the compiler when do_it<T>(T&, bool) is available
template<class T>
void do_it(T& t, ...)
{
}

// a compound class derived from any number of classes - I am so lazy I work hard at
// being lazy.
template<class...Templates>
struct C : public Templates...
{
    // construct from a parameter pack of arbitrary arguments
    // constructing each base class with one argument from the pack
    template<class...Args>
    C(Args&&...args)
    : Templates(std::forward<Args>(args))...
    {

    }

    // private implementation of the dispatch mechanism here...
private:
    // this will call ::do_it<T>(T&, bool) if T::do_it is a member function of T, otherwise
    // calls ::do_it<T>(T&, ...)
    template<class T>
    void may_do_it()
    {
        ::do_it(static_cast<T&>(*this), true);
    }

    // calls may_do_it for the last class in the parameter pack
    template<typename T1>
    void multi_may_do_it()
    {
        may_do_it<T1>();
    }

    // general case for calling do_it on a parameter pack of base classes
    template<typename T1, typename T2, typename...Rest>
    void multi_may_do_it()
    {
        may_do_it<T1>();
        multi_may_do_it<T2, Rest...>();
    }

    // calls may_do_it for the last class in the parameter pack
    template<typename T1>
    void multi_report() const
    {
        static_cast<const T1&>(*this).report();
    }

    // general case for calling do_it on a parameter pack of base classes
    template<typename T1, typename T2, typename...Rest>
    void multi_report() const
    {
        static_cast<const T1&>(*this).report();
        multi_report<T2, Rest...>();
    }


    // the functions we actually wish to expose here...
public:
    // disptach T::do_it for each valid T in base class list
    void do_it() {
        multi_may_do_it<Templates...>();
    }

    // dispatch T::report, which must exist for each base class
    void report() const {
        cout << "-- all base classes reporting:" << endl;
        multi_report<Templates...>();
        cout << "-- all base classes reported" << endl;
    }
};

int main()
{
    C<A,B, D, E> c(10, "hello", 7, "goodbye");
    c.report(); // all base classes must report
    c.do_it(); // all base classes that can do_it, must.

   return 0;
}

输出:

Compiling the source code....
$g++ -std=c++11 main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1

Executing the program....
$demo 
-- all base classes reporting:
10
hello
7
goodbye
-- all base classes reported
B did it with hello!
D did it with 7!


推荐答案

// a function enabled only if T::do_it is a member function pointer
template<class T>
auto do_it(T* t)
-> typename std::enable_if<std::is_member_function_pointer<decltype(&T::do_it)>::value, void>::type
{
    t->do_it();
}

// a catch-all function called when do_it<T> is not valid
// the const void * is less attractive to the compiler when do_it<T>(T*) is available
template<class T>
void do_it(const void *)
{
}

// a compound class derived from any number of classes - I am so lazy I work hard at
// being lazy.
template<class...Templates>
struct C : public Templates...
{
    //constructor omitted
private:
    using expander = int[];
public:
    // disptach T::do_it for each valid T in base class list
    void do_it() {
        (void) expander{ 0, (::do_it<Templates>(this), 0)...};
    }

    // dispatch T::report, which must exist for each base class
    void report() const {
        cout << "-- all base classes reporting:" << endl;
        (void) expander{ 0, (Templates::report(), 0)...};
        cout << "-- all base classes reported" << endl;
    }
};

演示

这篇关于C ++ 11对基类的模板参数包(如果存在)调用成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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