【发布时间】:2018-06-27 14:38:20
【问题描述】:
我想为类方法创建一个包装器,因此我使用了变量模板和 std::tuple 来包装该方法。它可以按我的需要工作,但我无法弄清楚如何能够使用通过引用调用的参数来包装方法。请看下面的主要功能。
#include <iostream>
#include <string>
#include <functional>
using namespace std::placeholders;
namespace helper {
template <std::size_t... Ts> struct index {};
template <std::size_t N, std::size_t... Ts> struct gen_seq : gen_seq<N - 1, N - 1, Ts...> {};
template <std::size_t... Ts> struct gen_seq<0, Ts...> : index<Ts...> {};
template<class F, class... Ts, std::size_t... Is> void for_each_in_tuple(std::tuple<Ts...> &tuple, F func, std::index_sequence<Is...>)
{
using expander = int[];
(void)expander {
0, ((void)func(std::get<Is>(tuple)), 0)...
};
}
template<class F, class...Ts> void for_each_in_tuple(std::tuple<Ts...> &tuple, F func)
{
for_each_in_tuple(tuple, func, std::make_index_sequence<sizeof...(Ts)>());
}
}
enum class Result : std::int32_t {
Result1 = 1,
Result2 = 2
};
template<typename... Args> class Procedure {
private:
std::function<Result(Args...)> m_method;
std::tuple<Args...> args;
template <typename... Args, std::size_t... Is> Result callMethod(std::tuple<Args...> &tup, helper::index<Is...>)
{
return m_method(std::get<Is>(tup)...);
}
template <typename... Args> Result callMethod(std::tuple<Args...> &tup)
{
return callMethod(tup, helper::gen_seq<sizeof...(Args)> {});
}
public:
template <typename ...Args> void setMethod(const std::function<Result(Args &&... args)> &method)
{
m_method = method;
}
};
class MethodsClass {
public:
Result doSomething(std::int32_t input, double output)
{
return Result::Result1;
}
};
int main()
{
**// This works fine**
MethodsClass methods;
Procedure <std::int32_t, double> procedure1;
procedure1.setMethod<std::int32_t, double>(std::bind(&MethodsClass::doSomething1, methods, _1, _2));
**// This end with compiler error std::tuple<int32_t,double &>::tuple': no appropriate default constructor available**
Procedure <std::int32_t, double &> procedure2;
procedure2.setMethod<std::int32_t, double &>(std::bind(&MethodsClass::doSomething2, methods, _1, _2));
return 0;
}
我知道为什么第二种情况无法编译,消息很清楚,很明显必须初始化引用。但是在这种情况下该怎么做呢?如何初始化 std:tuple,如何以及在哪里扩展参数包?我错过了一些东西,不知道是什么。
【问题讨论】:
-
您可能想了解标准库如何使用
std::reference_wrapper(这是由std::ref和std::cref创建的对象)。 -
有问题的
std::tuple<Args...> args;没有使用... -
std::function<Result(Args &&... args)>应该是std::function<Result(Args... args)>甚至是F&& f。 -
你在你的方法中隐藏你的类
Args...,最好使用不同的名字...... -
您的代码似乎没有足够注意调用的右值/左值上下文。如果我设置了一个过程,调用它的合法性和效率将取决于我是调用它并丢弃参数(即,从参数中移动)还是调用它并期望参数持续存在(也许我可以调用它不止一次)。二、你考虑过
std::function<void()>吗?
标签: c++ c++11 pass-by-reference variadic-templates stdtuple