如何将前 N 个参数传递给 C++ 函数
How to pass first N args to a C++ function
我有这样的功能:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
// data loading stuff
callback(body, subject, header);
}
问题是我不一定需要在回调函数中使用 subject
和 header
。现在我是这样处理的:
loadData([](std::string body, std::string, std::string){
std::cout << body;
})
我想替换成
loadData([](std::string body){
std::cout << body;
})
并自动将尽可能多的参数传递给回调函数。
我不想为所有 3 个可能的参数计数手动重载 loadData
函数。我也不想在调用站点上使用任何更复杂的 lambda 语法,因为我的库应该清楚供其他人使用。
这可能使用 C++ STL 和 Boost 吗?
使用 ...
忽略以下参数怎么样?
loadData([](std::string body, ...){
std::cout << body;
})
正如 StoryTeller 所指出的(谢谢!)对于非平凡的类型可能不支持使用省略号(有关详细信息,请参阅 [expr.call]p9)。
为了避免这个问题,如果你可以使用C++14,你可以使用auto ...
(更好的是auto && ...
以避免不必要的复制;谢谢Yakk)。
loadData([](std::string body, auto && ...){
std::cout << body;
})
您可以围绕 lambda 进行包装。
template<typename L>
struct OptionalWrapper {
OptionalWrapper(L l) : lambda{std::move(l)} {}
void operator()(std::string body, std::string subject, std::string header) const {
call(lambda, body, subject, header);
}
private:
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string header) const
-> decltype(l(body, subject, header))
{
return l(body, subject, header);
}
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string) const
-> decltype(l(body, subject))
{
return l(body, subject);
}
template<typename T>
auto call(T& l, std::string body, std::string, std::string) const
-> decltype(l(body))
{
return l(body);
}
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
然后,像这样使用包装器:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
callback(body, subject, header);
}
template<typename L>
void loadData(L callback)
{
loadData({makeOptionalWrapper(std::move(callback))});
}
我受到其他答案之一的启发,该答案建议制作一个包装器,将正确数量的参数传递给仿函数。我发现这个解决方案非常好,并且认为我会尝试制作一个通用的模板化包装器,其中参数的数量不是硬编码的。这是我想出的:
#include <string>
#include <functional>
#include <iostream>
struct WrapperHelp
{
template
< typename L
, typename Tuple
, std::size_t... Is
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, Ts&&... ts)
-> decltype(l(std::get<Is>(t)...))
{
return l(std::get<Is>(t)...);
}
template
< typename L
, typename Tuple
, std::size_t... Is
, typename T1
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, T1&& t1, Ts&&... ts)
-> decltype(WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) +1 >(), ts...))
{
return WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) + 1>(), ts...);
}
};
template<typename L>
struct OptionalWrapper {
public:
OptionalWrapper(L l) : lambda{std::move(l)} {}
template<typename... Ts>
void operator()(Ts&&... ts) const
{
WrapperHelp::apply(lambda, std::tuple<>(), std::index_sequence<>(), std::forward<Ts>(ts)...);
}
private:
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
template<class F>
void loadData(OptionalWrapper<F>&& callback)
{
std::string body = "body";
std::string subject = "subject";
std::string header = "header";
double lol = 2.0;
callback(body, subject, header, lol);
}
template<typename L>
void loadData(L callback)
{
loadData(makeOptionalWrapper(std::move(callback)));
}
int main() {
//apply(std::tuple<double>(2), std::tuple<double>(2));
loadData([](auto&& body) {
std::cout << body << std::endl;
});
loadData([](auto&& body, auto&& subject) {
std::cout << body << " " << subject << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header) {
std::cout << body << " " << subject << " " << header << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header, auto&& lol) {
std::cout << body << " " << subject << " " << header << " " << lol << std::endl;
});
return 0;
}
这应该适用于具有任意数量 "optional" 参数和任意类型参数的任何函数。这不是最漂亮的代码,但我希望这个想法很清楚并且可以使用 :)
我有这样的功能:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
// data loading stuff
callback(body, subject, header);
}
问题是我不一定需要在回调函数中使用 subject
和 header
。现在我是这样处理的:
loadData([](std::string body, std::string, std::string){
std::cout << body;
})
我想替换成
loadData([](std::string body){
std::cout << body;
})
并自动将尽可能多的参数传递给回调函数。
我不想为所有 3 个可能的参数计数手动重载 loadData
函数。我也不想在调用站点上使用任何更复杂的 lambda 语法,因为我的库应该清楚供其他人使用。
这可能使用 C++ STL 和 Boost 吗?
使用 ...
忽略以下参数怎么样?
loadData([](std::string body, ...){
std::cout << body;
})
正如 StoryTeller 所指出的(谢谢!)对于非平凡的类型可能不支持使用省略号(有关详细信息,请参阅 [expr.call]p9)。
为了避免这个问题,如果你可以使用C++14,你可以使用auto ...
(更好的是auto && ...
以避免不必要的复制;谢谢Yakk)。
loadData([](std::string body, auto && ...){
std::cout << body;
})
您可以围绕 lambda 进行包装。
template<typename L>
struct OptionalWrapper {
OptionalWrapper(L l) : lambda{std::move(l)} {}
void operator()(std::string body, std::string subject, std::string header) const {
call(lambda, body, subject, header);
}
private:
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string header) const
-> decltype(l(body, subject, header))
{
return l(body, subject, header);
}
template<typename T>
auto call(T& l, std::string body, std::string subject, std::string) const
-> decltype(l(body, subject))
{
return l(body, subject);
}
template<typename T>
auto call(T& l, std::string body, std::string, std::string) const
-> decltype(l(body))
{
return l(body);
}
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
然后,像这样使用包装器:
void loadData(std::function<void (std::string, std::string, std::string)> callback)
{
callback(body, subject, header);
}
template<typename L>
void loadData(L callback)
{
loadData({makeOptionalWrapper(std::move(callback))});
}
我受到其他答案之一的启发,该答案建议制作一个包装器,将正确数量的参数传递给仿函数。我发现这个解决方案非常好,并且认为我会尝试制作一个通用的模板化包装器,其中参数的数量不是硬编码的。这是我想出的:
#include <string>
#include <functional>
#include <iostream>
struct WrapperHelp
{
template
< typename L
, typename Tuple
, std::size_t... Is
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, Ts&&... ts)
-> decltype(l(std::get<Is>(t)...))
{
return l(std::get<Is>(t)...);
}
template
< typename L
, typename Tuple
, std::size_t... Is
, typename T1
, typename... Ts
>
static auto apply(L&& l, Tuple t, std::index_sequence<Is...>, T1&& t1, Ts&&... ts)
-> decltype(WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) +1 >(), ts...))
{
return WrapperHelp::apply(std::forward<L>(l), std::forward_as_tuple(std::get<Is>(t)..., t1), std::make_index_sequence<sizeof...(Is) + 1>(), ts...);
}
};
template<typename L>
struct OptionalWrapper {
public:
OptionalWrapper(L l) : lambda{std::move(l)} {}
template<typename... Ts>
void operator()(Ts&&... ts) const
{
WrapperHelp::apply(lambda, std::tuple<>(), std::index_sequence<>(), std::forward<Ts>(ts)...);
}
private:
L lambda;
};
template<typename L>
auto makeOptionalWrapper(L l) { return OptionalWrapper<L>{std::move(l)}; }
template<class F>
void loadData(OptionalWrapper<F>&& callback)
{
std::string body = "body";
std::string subject = "subject";
std::string header = "header";
double lol = 2.0;
callback(body, subject, header, lol);
}
template<typename L>
void loadData(L callback)
{
loadData(makeOptionalWrapper(std::move(callback)));
}
int main() {
//apply(std::tuple<double>(2), std::tuple<double>(2));
loadData([](auto&& body) {
std::cout << body << std::endl;
});
loadData([](auto&& body, auto&& subject) {
std::cout << body << " " << subject << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header) {
std::cout << body << " " << subject << " " << header << std::endl;
});
loadData([](auto&& body, auto&& subject, auto&& header, auto&& lol) {
std::cout << body << " " << subject << " " << header << " " << lol << std::endl;
});
return 0;
}
这应该适用于具有任意数量 "optional" 参数和任意类型参数的任何函数。这不是最漂亮的代码,但我希望这个想法很清楚并且可以使用 :)