[英]Template tuple - calling a function on each element
我的問題是在代碼中:
template<typename... Ts>
struct TupleOfVectors {
std::tuple<std::vector<Ts>...> tuple;
void do_something_to_each_vec() {
//Question: I want to do this:
// "for each (N)": do_something_to_vec<N>()
//How?
}
template<size_t N>
void do_something_to_vec() {
auto &vec = std::get<N>(tuple);
//do something to vec
}
};
你可以很容易地用一些索引機制來做到這一點。 給定一個用於生成編譯時整數序列的元函數gen_seq
(由seq
類模板封裝):
namespace detail
{
template<int... Is>
struct seq { };
template<int N, int... Is>
struct gen_seq : gen_seq<N - 1, N - 1, Is...> { };
template<int... Is>
struct gen_seq<0, Is...> : seq<Is...> { };
}
以及以下功能模板:
#include <tuple>
namespace detail
{
template<typename T, typename F, int... Is>
void for_each(T&& t, F f, seq<Is...>)
{
auto l = { (f(std::get<Is>(t)), 0)... };
}
}
template<typename... Ts, typename F>
void for_each_in_tuple(std::tuple<Ts...> const& t, F f)
{
detail::for_each(t, f, detail::gen_seq<sizeof...(Ts)>());
}
你可以這樣使用上面的for_each_in_tuple
函數:
#include <string>
#include <iostream>
struct my_functor
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
int main()
{
std::tuple<int, double, std::string> t(42, 3.14, "Hello World!");
for_each_in_tuple(t, my_functor());
}
這是一個活生生的例子。
在您的具體情況下,您可以這樣使用它:
template<typename... Ts>
struct TupleOfVectors
{
std::tuple<std::vector<Ts>...> t;
void do_something_to_each_vec()
{
for_each_in_tuple(t, tuple_vector_functor());
}
struct tuple_vector_functor
{
template<typename T>
void operator () (T const &v)
{
// Do something on the argument vector...
}
};
};
再一次,這是一個活生生的例子。
如果您使用C++14或更高版本,您可以用std::integer_sequence
替換上面的seq
和gen_seq
類,如下所示:
namespace detail
{
template<typename T, typename F, int... Is>
void
for_each(T&& t, F f, std::integer_sequence<int, Is...>)
{
auto l = { (f(std::get<Is>(t)), 0)... };
}
} // namespace detail
template<typename... Ts, typename F>
void
for_each_in_tuple(std::tuple<Ts...> const& t, F f)
{
detail::for_each(t, f, std::make_integer_sequence<int, sizeof...(Ts)>());
}
如果您使用的是C++17或更高版本,則可以執行此操作(來自下面的評論):
std::apply([](auto ...x){std::make_tuple(some_function(x)...);} , the_tuple);
在 C++17 中,你可以這樣做:
std::apply([](auto ...x){std::make_tuple(some_function(x)...);} , the_tuple);
鑒於some_function
對元組中的所有類型都有合適的重載。
這已經適用於 Clang++ 3.9,使用std::experimental::apply
。
除了@M的回答。 Alaggan,如果需要調用元組元素的函數在它們的元組中的外觀†的順序,在C ++ 17也可以用一個倍的表達這樣的:
std::apply([](auto& ...x){(..., some_function(x));}, the_tuple);
( 活生生的例子)。
†因為否則函數參數的計算順序是未指定的。
這是一種可能適用於您的情況的方法:
template<typename... Ts>
struct TupleOfVectors {
std::tuple<std::vector<Ts>...> tuple;
void do_something_to_each_vec()
{
// First template parameter is just a dummy.
do_something_to_each_vec_helper<0,Ts...>();
}
template<size_t N>
void do_something_to_vec()
{
auto &vec = std::get<N>(tuple);
//do something to vec
}
private:
// Anchor for the recursion
template <int>
void do_something_to_each_vec_helper() { }
// Execute the function for each template argument.
template <int,typename Arg,typename...Args>
void do_something_to_each_vec_helper()
{
do_something_to_each_vec_helper<0,Args...>();
do_something_to_vec<sizeof...(Args)>();
}
};
這里唯一有點混亂的是do_something_to_each_vec_helper
的額外虛擬int
模板參數。 當沒有參數剩余時,有必要使 do_something_to_each_vec_helper 仍然是模板。 如果您有另一個要使用的模板參數,您可以在那里使用它。
如果您不是特別熱衷於通用“for each”函數模板形式的解決方案,那么您可以使用這樣的:
#ifndef TUPLE_OF_VECTORS_H
#define TUPLE_OF_VECTORS_H
#include <vector>
#include <tuple>
#include <iostream>
template<typename... Ts>
struct TupleOfVectors
{
std::tuple<std::vector<Ts>...> tuple;
template<typename ...Args>
TupleOfVectors(Args... args)
: tuple(args...){}
void do_something_to_each_vec() {
do_something_to_vec(tuple);
}
template<size_t I = 0, class ...P>
typename std::enable_if<I == sizeof...(P)>::type
do_something_to_vec(std::tuple<P...> &) {}
template<size_t I = 0, class ...P>
typename std::enable_if<I < sizeof...(P)>::type
do_something_to_vec(std::tuple<P...> & parts) {
auto & part = std::get<I>(tuple);
// Doing something...
std::cout << "vector[" << I << "][0] = " << part[0] << std::endl;
do_something_to_vec<I + 1>(parts);
}
};
#endif // EOF
使用 GCC 4.7.2 和 clang 3.2 構建的測試程序:
#include "tuple_of_vectors.h"
using namespace std;
int main()
{
TupleOfVectors<int,int,int,int> vecs(vector<int>(1,1),
vector<int>(2,2),
vector<int>(3,3),
vector<int>(4,4));
vecs.do_something_to_each_vec();
return 0;
}
可以在沒有輔助索引裝置的通用“for_each”函數模板中使用相同風格的遞歸:
#ifndef FOR_EACH_IN_TUPLE_H
#define FOR_EACH_IN_TUPLE_H
#include <type_traits>
#include <tuple>
#include <cstddef>
template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I == sizeof...(Ts)>::type
for_each_in_tuple(std::tuple<Ts...> &, Func) {}
template<size_t I = 0, typename Func, typename ...Ts>
typename std::enable_if<I < sizeof...(Ts)>::type
for_each_in_tuple(std::tuple<Ts...> & tpl, Func func)
{
func(std::get<I>(tpl));
for_each_in_tuple<I + 1>(tpl,func);
}
#endif //EOF
和一個測試程序:
#include "for_each_in_tuple.h"
#include <iostream>
struct functor
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
int main()
{
auto tpl = std::make_tuple(1,2.0,"Three");
for_each_in_tuple(tpl,functor());
return 0;
}
我正在使用元組和元編程進行測試,並找到了當前線程。 雖然我喜歡@Andy 的解決方案,但我認為我的工作可以激勵其他人。
無論如何,盡情享受吧!
#include <tuple>
#include <type_traits>
#include <iostream>
#include <sstream>
#include <functional>
template<std::size_t I = 0, typename Tuple, typename Func>
typename std::enable_if< I != std::tuple_size<Tuple>::value, void >::type
for_each(const Tuple& tuple, Func&& func)
{
func(std::get<I>(tuple));
for_each<I + 1>(tuple, func);
}
template<std::size_t I = 0, typename Tuple, typename Func>
typename std::enable_if< I == std::tuple_size<Tuple>::value, void >::type
for_each(const Tuple& tuple, Func&& func)
{
// do nothing
}
struct print
{
template<typename T>
void operator () (T&& t)
{
std::cout << t << std::endl;
}
};
template<typename... Params>
void test(Params&& ... params)
{
int sz = sizeof...(params);
std::tuple<Params...> values(std::forward<Params>(params)...);
for_each(values, print() );
}
class MyClass
{
public:
MyClass(const std::string& text)
: m_text(text)
{
}
friend std::ostream& operator <<(std::ostream& stream, const MyClass& myClass)
{
stream << myClass.m_text;
return stream;
}
private:
std::string m_text;
};
int main()
{
test(1, "hello", 3.f, 4, MyClass("I don't care") );
}
Boost mp11 具有以下功能:
#include <iostream>
#include <string>
#include <boost/mp11.hpp>
using namespace std;
using boost::mp11::tuple_for_each;
std::tuple t{string("abc"), 47 };
int main(){
tuple_for_each(t,[](const auto& x){
cout << x + x << endl;
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.