将可变函数作为参数传递
Passing a variadic function as argument
考虑这个工作代码:
#include <iostream>
#include <utility>
#include <array>
template <typename... Args>
void foo (Args&&... args) {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
template <typename> struct Foo;
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container>
static void execute (const Container& v) {
foo(v[Is]...);
}
};
template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
Foo<std::make_index_sequence<N>>::execute(a);
}
int main() {
fooArray<6>({0,1,2,3,4,5}); // 0 1 2 3 4 5
}
我现在想像这样概括 Foo
结构:
#include <iostream>
#include <utility>
#include <array>
template <typename... Args>
void foo (Args&&... args) {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
template <typename> struct Foo;
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container, typename F> // *** Modified
static void execute (const Container& v, F f) {
f(v[Is]...);
}
};
template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
Foo<std::make_index_sequence<N>>::execute(a, foo);
}
int main() {
fooArray<6>({0,1,2,3,4,5});
}
但是我得到一个编译错误(来自 GCC 4.9.2),无法推导出 F。我该如何实现?
foo
是重载系列,因此 foo
不明确。
(甚至 foo<int, int>
也是,因为它也可能有其他类型)。
您可以强制执行预期类型函数,如下所示:
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container>
static void execute (const Container& v, void (*f)(decltype(v[Is])&...)) {
f(v[Is]...);
}
};
另一种方法是将函数 foo
包装到 class:
class FooCaller
{
public:
template <typename... Args>
void operator () (Args&&... args) const {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
};
并保留您的实施:
模板不是一个单一的东西。您不能将模板函数作为函数或对象传递。现在,重载集的名称(例如,foo
)可以在特定上下文中解析为模板函数的单个实例(您调用它的地方,或将其转换为函数指针),这可能就是愚弄您的原因.
如果您想将整个重载集作为一个对象来使用,您可以通过以下方式对其进行近似:
struct foo_f{
template<class...Args>
auto operator()(Args&&...args)const->
decltype(foo(std::declval<Args>()...))
{ return foo(std::forward<Args>(args)...); }
};
现在 foo_f
的实例将 foo
的重载集近似为单个对象。通过 foo_f{}
代替 foo
.
在 C++14 中,或者:
[](auto&&...args)->decltype(auto){return foo(decltype(args)(args)...);}
是一个与上面的 foo_f
非常相似的 lambda。
考虑这个工作代码:
#include <iostream>
#include <utility>
#include <array>
template <typename... Args>
void foo (Args&&... args) {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
template <typename> struct Foo;
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container>
static void execute (const Container& v) {
foo(v[Is]...);
}
};
template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
Foo<std::make_index_sequence<N>>::execute(a);
}
int main() {
fooArray<6>({0,1,2,3,4,5}); // 0 1 2 3 4 5
}
我现在想像这样概括 Foo
结构:
#include <iostream>
#include <utility>
#include <array>
template <typename... Args>
void foo (Args&&... args) {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
template <typename> struct Foo;
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container, typename F> // *** Modified
static void execute (const Container& v, F f) {
f(v[Is]...);
}
};
template <std::size_t N>
void fooArray (const std::array<int, N>& a) {
Foo<std::make_index_sequence<N>>::execute(a, foo);
}
int main() {
fooArray<6>({0,1,2,3,4,5});
}
但是我得到一个编译错误(来自 GCC 4.9.2),无法推导出 F。我该如何实现?
foo
是重载系列,因此 foo
不明确。
(甚至 foo<int, int>
也是,因为它也可能有其他类型)。
您可以强制执行预期类型函数,如下所示:
template <std::size_t... Is>
struct Foo<std::index_sequence<Is...>> {
template <typename Container>
static void execute (const Container& v, void (*f)(decltype(v[Is])&...)) {
f(v[Is]...);
}
};
另一种方法是将函数 foo
包装到 class:
class FooCaller
{
public:
template <typename... Args>
void operator () (Args&&... args) const {
const auto v = {args...};
for (auto x : v) std::cout << x << ' '; std::cout << '\n';
}
};
并保留您的实施:
模板不是一个单一的东西。您不能将模板函数作为函数或对象传递。现在,重载集的名称(例如,foo
)可以在特定上下文中解析为模板函数的单个实例(您调用它的地方,或将其转换为函数指针),这可能就是愚弄您的原因.
如果您想将整个重载集作为一个对象来使用,您可以通过以下方式对其进行近似:
struct foo_f{
template<class...Args>
auto operator()(Args&&...args)const->
decltype(foo(std::declval<Args>()...))
{ return foo(std::forward<Args>(args)...); }
};
现在 foo_f
的实例将 foo
的重载集近似为单个对象。通过 foo_f{}
代替 foo
.
在 C++14 中,或者:
[](auto&&...args)->decltype(auto){return foo(decltype(args)(args)...);}
是一个与上面的 foo_f
非常相似的 lambda。