具有可变参数模板的函数对象
Function objects with variadic template
如何定义可以传递给应用程序的函数对象?最终,我想要一个函数 F f 可以获取元组的所有元素并将它们推回一个向量。
template <class F, size_t... Is>
constexpr auto index_apply_impl(F f, index_sequence<Is...>) {
return f(integral_constant<size_t, Is> {}...);
}
template <size_t N, class F>
constexpr auto index_apply(F f) {
return index_apply_impl(f, make_index_sequence<N>{});
}
template <class Tuple, class F>
constexpr auto apply(Tuple t, F f) {
return index_apply<tuple_size<Tuple>{}>(
[&](auto... Is) { return f(get<Is>(t)...); });
}
谢谢:)
可以使用expander trick。不过这需要 C++14。我不知道你的字节数组格式是什么样的,所以我只是采用了一个带有字符串成员的通用结构,并在构造函数中将所有内容都转换为字符串。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
template < typename T, typename F, size_t ... Is >
void for_each_impl(T&& t, F&& f, std::index_sequence<Is...>)
{
using expand_type = int[];
(void) expand_type { 0, ( (void) f(std::get<Is>(t)), 0) ... };
}
template < typename... Args, typename F >
void for_each(std::tuple<Args...> const& t, F&& f)
{
for_each_impl(t, f, std::make_index_sequence<sizeof...(Args)>{});
}
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
for_each(t, [&v](auto&& x){ v.push_back(x); });
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}
在 C++17 中,这要容易得多,这要归功于可变参数 lambda,fold expression, and std::apply
。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
std::apply([&v](auto&&... x){ (... , v.push_back(x)); }, t);
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}
如果你不能使用 C++11,你的生活将是痛苦的。您必须推出自己的 index_sequence
实现,并且必须使用模板化调用运算符定义辅助结构来替换通用 lambda。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
//
template <size_t ...I>
struct index_sequence {};
template <size_t N, size_t ...I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <size_t ...I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
// Call a function for each element in a tuple
template < typename T, typename F, size_t ... Is >
void for_each_impl(T&& t, F&& f, index_sequence<Is...>)
{
using expand_type = int[];
(void) expand_type { 0, ( (void) f(std::get<Is>(t)), 0) ... };
}
template < typename... Args, typename F >
void for_each(std::tuple<Args...> const& t, F&& f)
{
for_each_impl(t, f, make_index_sequence<sizeof...(Args)>{});
}
// "Byte array" emulation
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
// Surrogate template lambda
struct Visitor
{
std::vector<Bytes>& v;
Visitor(std::vector<Bytes>& vb) : v(vb) {};
template < typename T >
void operator() (T&& x) { v.push_back(x); }
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
for_each(t, Visitor(v));
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}
如何定义可以传递给应用程序的函数对象?最终,我想要一个函数 F f 可以获取元组的所有元素并将它们推回一个向量。
template <class F, size_t... Is>
constexpr auto index_apply_impl(F f, index_sequence<Is...>) {
return f(integral_constant<size_t, Is> {}...);
}
template <size_t N, class F>
constexpr auto index_apply(F f) {
return index_apply_impl(f, make_index_sequence<N>{});
}
template <class Tuple, class F>
constexpr auto apply(Tuple t, F f) {
return index_apply<tuple_size<Tuple>{}>(
[&](auto... Is) { return f(get<Is>(t)...); });
}
谢谢:)
可以使用expander trick。不过这需要 C++14。我不知道你的字节数组格式是什么样的,所以我只是采用了一个带有字符串成员的通用结构,并在构造函数中将所有内容都转换为字符串。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
template < typename T, typename F, size_t ... Is >
void for_each_impl(T&& t, F&& f, std::index_sequence<Is...>)
{
using expand_type = int[];
(void) expand_type { 0, ( (void) f(std::get<Is>(t)), 0) ... };
}
template < typename... Args, typename F >
void for_each(std::tuple<Args...> const& t, F&& f)
{
for_each_impl(t, f, std::make_index_sequence<sizeof...(Args)>{});
}
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
for_each(t, [&v](auto&& x){ v.push_back(x); });
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}
在 C++17 中,这要容易得多,这要归功于可变参数 lambda,fold expression, and std::apply
。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
std::apply([&v](auto&&... x){ (... , v.push_back(x)); }, t);
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}
如果你不能使用 C++11,你的生活将是痛苦的。您必须推出自己的 index_sequence
实现,并且必须使用模板化调用运算符定义辅助结构来替换通用 lambda。
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
//
template <size_t ...I>
struct index_sequence {};
template <size_t N, size_t ...I>
struct make_index_sequence : public make_index_sequence<N - 1, N - 1, I...> {};
template <size_t ...I>
struct make_index_sequence<0, I...> : public index_sequence<I...> {};
// Call a function for each element in a tuple
template < typename T, typename F, size_t ... Is >
void for_each_impl(T&& t, F&& f, index_sequence<Is...>)
{
using expand_type = int[];
(void) expand_type { 0, ( (void) f(std::get<Is>(t)), 0) ... };
}
template < typename... Args, typename F >
void for_each(std::tuple<Args...> const& t, F&& f)
{
for_each_impl(t, f, make_index_sequence<sizeof...(Args)>{});
}
// "Byte array" emulation
struct Bytes {
std::string str;
Bytes(char const * c) : str(c) {};
Bytes(int i) : str(std::to_string(i)) {};
Bytes(char c) : str(1, c) {};
};
// Surrogate template lambda
struct Visitor
{
std::vector<Bytes>& v;
Visitor(std::vector<Bytes>& vb) : v(vb) {};
template < typename T >
void operator() (T&& x) { v.push_back(x); }
};
int main()
{
auto t = std::make_tuple(12, "abc", 10, 'c', 1);
std::vector<Bytes> v;
for_each(t, Visitor(v));
for (auto const& e : v)
std::cout << e.str << ' ';
std::cout << '\n';
}