在c ++ 11中,我有非常简洁的工作代码,用于按类型提取std::tuple
项目(因为我知道此功能甚至placed到c ++ 14 stl)
现在我面临着通过继承的类规范
选择项目的任务 struct A
{
int a;
};
struct B : public A
{
int b;
};
...
auto tval = std::make_tuple(1, B());
//now I would like to reference items as following:
tuple_ref_by_inheritance<A>(tval).a = 5; //Access to B instance by parent A
以下代码是不成功尝试:
template< class T, class Tuple >
struct tuple_ref_index;
// recursive case
template<class T, class Head, class... Tail >
struct tuple_ref_index<T, std::tuple<Head, Tail...> >
{
enum { value = tuple_ref_index<T, std::tuple<Tail...>>::value + 1 };
};
template<class T, class Head, class... Tail >
struct tuple_ref_index<T, std::tuple<Head, Tail...> >
{
const static typename std::enable_if<
std::is_same<T, Head>::value>::type* _= nullptr;
enum { value = 0 };
};
template <class T, class Tuple>
inline T& tuple_ref_by_inheritance(Tuple& tuple)
{
return std::get< tuple_ref_index<T, Tuple>::value >(tuple);
}
答案 0 :(得分:6)
require 'stb_helper'
class Stb < ActiveRecord::Base
def self.get_notes_data
.
.
.
end
def self.update
.
.
.
end
def self.report(options={})
csv_file = nil
if options == {}
########################################
# This is the line that throws the error
csv_file = StbHelper.gen_csv(Stb.all)
#######################################
else
stbs = []
customers = List.where(id: options[:list])[0].customers
customers.each do |customer|
customer.accounts.each do |account|
stbs += account.stbs
end
end
csv_file = StbHelper.gen_csv(stbs)
end
end
end
答案 1 :(得分:2)
首先,一些元编程样板。
void_t
是C ++ 14:
namespace details {
template<class...>struct voider{using type=void;};
}
template<class...Ts>
using void_t=typename details::voider<Ts...>::type;
这会对列表的每个元素进行测试,并返回第一个传递的测试:
template<template<class...>class Test, class List>
struct get_first_that_passes;
template<template<class...>class Test, class List>
using get_first_that_passes_t=
typename get_first_that_passes<Test,List>::type;
namespace details {
template<template<class...>class, class, class...>
struct get_first_pass {};
template<template<class...>class Test, class T0, class...Ts>
struct get_first_pass<Test, std::enable_if_t< !Test<T0>::value >, T0, Ts...> :
get_first_pass<Test, void, Ts...>
{};
template<template<class...>class Test, class T0, class...Ts>
struct get_first_pass<Test, std::enable_if_t< Test<T0>::value >, T0, Ts...> {
using type=T0;
};
}
template<template<class...>class Test, template<class...>class List, class...Ts>
struct get_first_that_passes<Test, List<Ts...>>:
details::get_first_pass<Test, void, Ts...>
{};
现在我们编写is_derived_from
,如果某个东西是从基础派生的话,会产生一个测试:
template<class Base>
struct is_derived_from {
template<class Derived>
using test = std::is_base_of<Base,Derived>;
};
通过编写上面的两个,我们得到了一个从某个基础派生的列表中的第一个类型:
template<class Base, class List>
using get_first_derived =
get_first_that_passes_t<
is_derived_from<Base>::template test,
List
>;
允许我们编写一个简单的get_from_base<T>(tuple)
,其中tuple
中的第一个类型派生自T
,然后在其上调用std::get<T>
:
template<class Base, class Tuple>
auto get_from_base( Tuple&& tuple )
->decltype(std::get< get_first_derived<Base, std::decay_t<Tuple>> >(std::forward<Tuple>(tuple)))
{ return std::get< get_first_derived<Base, std::decay_t<Tuple>> >(std::forward<Tuple>(tuple)); }
将其转换为C ++ 11留作练习。 (删除_t
可能就够了。)
请注意,写完后,它会找到第一个派生自Base
的类型。然后它将返回对该元素的引用,但前提是列表中没有类型的实例。
要匹配get<Type>
,您需要确认尾部没有源自Base
的其他类型。
如果你想要get_first_that_derives_from
,你必须得到索引而不是类型。