对每个数据成员应用相同的函数 - 对异构类型进行转换
Apply the same function to each data member - Transform on heterogeneous types sort of thing
请考虑以下结构:
struct Test {
char a;
short b;
int c;
long long d;
void transformTest() {
// Pseudo
foreach datamember (regardless of type) of Test
call someTransform(datamember)
}
};
我们还可以将lambda,函数指针,functor,任何东西传递到transformTest()中,这不是我现在关心的问题。
最好的方法是什么?
最好的方法是明确地执行此操作:
someTransform(a);
someTransform(b);
someTransform(c);
someTransform(d);
当然,您需要适当数量的重载someTransform()
。
真的不喜欢这样,总会有Boost Fusion。 有了它,您可以将您的值放在一个库理解的结构中,然后可以迭代。 对于简单的用例,这是不值得的。
听起来像是Boost Fusion及其for_each()
功能与BOOST_FUSION_ADAPT_STRUCT相结合的案例。这东西可以创造一些奇迹!下面是有关如何执行此操作的示例:
#include <boost/fusion/include/algorithm.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
using namespace boost::fusion;
struct Print
{
template <typename T>
void operator()( T && t ) const
{
std::cout << t << ' ';
}
};
struct Test {
char a;
short b;
int c;
long long d;
void printTest() const;
};
BOOST_FUSION_ADAPT_STRUCT(
Test,
(char, a)
(short, b)
(int, c)
(long long, d)
)
void Test::printTest() const
{
for_each ( *this, Print() );
}
int main()
{
const auto t = Test();
t.printTest();
}
第 1 步:将数据包装在tuple
中。 可能是暂时的。
第 2 步:将可调用对象包装在函子中。
第 3 步:编写一个将函子应用于tuple
的每个元素的tuple_foreach
。
对于第 1 步,我建议将数据保留在原处,只需使用 std::tie
来创建引用tuple
。
对于步骤 2,一个简单的完美转发函子如下所示:
#define RETURNS(X) ->decltype(X) { return (X); }
struct foo_functor {
template<typename... Args>
auto operator()(Args&&... args) const
RETURNS( foo( std::forward<Args>(args)... ) )
};
它表示称为 foo
的函数的覆盖集,并将其包装到单个对象中,该对象会自动将任何调用调度到适当的 foo
重载。
对于第 3 步,这并不难。 只需使用索引技巧在tuple
的每个元素上运行代码:
void do_in_order() {}
template<typename Lambda, typename... Lambdas>
void do_in_order( Lambda&& closure, Lambdas&&... closures ) {
std::forward<Lambda>(closure)();
do_in_order( std::forward<Lambdas>(closures)... );
}
template<unsigned... Is>
struct seq { typedef seq<Is> type; }
template<unsigned Max, unsigned... Is>
struct make_seq:make_seq<Max-1, Max-1, Is...> {};
template<unsigned... Is>
struct make_seq<0,Is...>:seq<Is...> {};
template<typename Tuple, typename Functor, unsigned... Is>
void foreach_tuple_helper( seq<Is...>, Tuple&& t, Functor&& f ) {
do_in_order(
[&]{ std::forward<Functor>(f)(std::get<Is>(std::forward<Tuple>(t))); }...
);
}
template<typename Tuple, typename Functor>
void foreach_tuple( Tuple&& t, Functor&& f ) {
foreach_tuple_helper( make_seq<std::tuple_size< typename std::decay<Tuple>::type >::value>(), std::forward<Tuple>(t), std::forward<Functor>(f) );
}
do_in_order
在我上次检查的 clang 中不起作用,但适用于编译器的等效索引技巧应该不难谷歌。
虽然 Boost.Fusion 是一个很好的解决方案,但我想我会在 C++11 中添加一个,您可以使用这样的std::tuple
:
template <unsigned ... indices>
struct sequence
{
typedef sequence type;
};
template <unsigned size, unsigned ... indices>
struct static_range : static_range<size-1,size-1,indices...> {};
template <unsigned ... indices>
struct static_range<0, indices...> : sequence<indices...> {};
template <class Function, class Tuple, unsigned ... indices>
auto transform_impl(const Tuple & t, Function f, sequence<indices...>) ->
std::tuple<decltype(f(std::get<indices>(t)))...>
{
return std::make_tuple(f(std::get<indices>(t))...);
}
template <class Function, class Tuple>
auto transform_tuple(const Tuple & t, Function f) ->
decltype(transform_impl(t, f, static_range<std::tuple_size<Tuple>::value>()))
{
return transform_impl(t, f, static_range<std::tuple_size<Tuple>::value>());
}
sequence
/static_range
类在我的代码中非常宝贵,可以通过索引扩展类(不仅仅是std::tuple
s),以便我可以std::get
它们。
除此之外,我认为代码相当简单,但是应该注意的是,使用此方法,在每个元组元素上调用f
的顺序是未定义的。
用法如下所示:
std::tuple<char, short, int, long long> t;
struct addone
{ template <class T> auto operator()(T t) -> decltype(t+1) {return t + 1;}};
auto t2 = transform_tuple(t, addone());
由于积分提升,生成的元组将不具有与输入元组相同的类型,每个元组将具有类型 typename std::common_type<T,int>::type
。
- 在C++中,如何创建包含可变模板对象的异构向量?
- 创建异构顶点数据数组的可移植方法
- std::variant vs指向C++中异构容器基类的指针
- C++中的集合(异构类型的数组)
- 从异构列表中提取数据
- Push_back一组(异构)向量的实现
- 使用 std::vector<char> 作为异构记录的存储是否安全?
- 是否可以使用 std::vector<std::any> vec;这将导致异构数据类型
- C++异构类型迭代器的迭代器
- 异构变量非类型模板参数计数是否灵活
- 使用C++可变模板,我如何存储一组异构类型的对象并对它们进行迭代
- 具有按类型安全查找的可变大小异构容器
- 异构类型的c++数组
- 对每个数据成员应用相同的函数 - 对异构类型进行转换
- 异构类型的成员函数映射
- 从Bloch的Effective Java in C++实现类型安全的异构容器(VS2010)
- 用异构boost::融合向量类型数据填充std::vector
- 模板异构类型的集合
- 如何显式管理异构类型(和大小)的多个池分配器
- C++异构类型列的表(集合)