带有任何参数的模板仿函数

时间:2016-12-07 13:55:34

标签: c++ templates variadic-templates

我正在尝试创建模板仿函数,它将使用任意数量的参数作为参数对象和成员函数。我无法弄清楚如何使用模板正确编写代码。

template<typename ItemT,
     class T,
     typename ...Args>
struct Builder
{
    ItemT operator()(T& object, ItemT (T::*method)(Args...), Args && ... args)
    {
        return (object.*method)(std::forward<Args>(args)...);
    }
};

struct Object
{
    int method(int, int, int) { return 4; }
};


int main()
{
    Object obj;    
    Builder<int, Object>()(obj, &Object::method); // Error here
}

如果我使用没有参数的Object ::方法 - 代码编译。但有参数 - 没有。

严重级代码描述项目文件行抑制状态 错误C2664'int Builder :: operator()(T&amp;,ItemT(__ thishisall Object :: *)(void))':无法从'int(__thiscall Object :: *)(int,int,int)转换参数2 'to'int(__ thiscall Object :: *)(void)'草稿c:\ drafts \ main.cpp 139

2 个答案:

答案 0 :(得分:4)

假设您不想更改import React, {PropTypes} from 'react'; import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; import {asyncConnect} from 'redux-async-connect'; import {load, isLoaded} from 'redux/modules/viewlodging'; @asyncConnect([{ promise: ({ store: { dispatch, getState } }) => { const promises = []; if (!isLoaded(getState())) { promises.push(dispatch(load())); } return Promise.all(promises); } }]) @connect( state => ({ viewdata: state.viewlodging.data }), dispatch => bindActionCreators({ load }, dispatch) ) export default class Product extends React.Component { static propTypes = { viewdata: PropTypes.object, location: PropTypes.object, load: PropTypes.func.isRequired } componentDidMount(){ const {id} = this.props.params; this.props.load(id); //you can send params values after component get mounted. } render() { console.log(this.props.routeParams.id); // here I get routeparameter //don't send in render method, since it'll be called many times const { viewdata } = this.props; return ( < div > < div > Sample test < /div> < /div> < Footer / > < Viewfootertext viewdata = { viewdata } /> < /div> ); } } 的当前定义,您需要实例化它:

Builder

Builder<int, Object, int, int, int>()(obj, &Object::method, 0, 0, 0); // ^ ^ ^^^^^^^^^^^^^ ^^^^^^^ // ItemT | | | // T Args... args... 调用中的args...参数展开必须与传递给operator()的{​​{1}}包一致。

wandbox example

这是另一种不太严格的设计:

TArgs...

以上Builder可以这样使用:

template<typename T>
struct Builder
{
    template <typename TFnPtr, typename... Args>
    auto operator()(T& object, TFnPtr method, Args && ... args)
    {
        return (object.*method)(std::forward<Args>(args)...);
    }
};

在这种情况下,成员函数指针的类型是通过Builder推导出来的,并不限于任何特定的参数集。可变参数不再是int main() { Object obj; Builder<Object>()(obj, &Object::method, 0, 0, 0); } 的一部分 - 它们属于TFnPtr的一部分,因此可以推导出它们并转发给Builder

wandbox example

答案 1 :(得分:1)

您可以完全避免在Builder上进行模板操作,并且完全依赖于模板参数推断:

struct Builder {
    template <typename Obj, typename R, typename ... FArgs, typename ... Args>
    R operator()(Obj& obj, R (Obj::*fn)(FArgs...), Args&&... args) {
        return (obj.*fn)(std::forward<Args>(args)...);
    }
};

我选择使用两个参数包来实现完美转发:operator()调用的值类别不一定与目标方法匹配。这也允许在应用成员函数指针时隐式转换参数。请注意,此实现与const的{​​{1}}方法不匹配。

你当然可以使用Obj返回类型(C ++ 14)或尾随返回类型(C ++ 11)来放松一下。由于Vittorio的答案已经向您呈现了C ++ 14方式,我将解决后者问题。然后auto变为:

operator()

然后,用法只是:

template <typename Obj, typename FnPtr, typename ... Args>
auto operator()(Obj& obj, FnPtr fn, Args&&... args)
    -> decltype((obj.*fn)(std::forward<Args>(args)...)) {
    return (obj.*fn)(std::forward<Args>(args)...);
}
Coliru上的

live demo