将 BOUNDED std::list<class> 参数转换为类型 std::tuple<class,class,class> tup<classObj1, classObj2,classObj2>
Turning a BOUNDED std::list<class> of parameters into a type std::tuple<class,class,class> tup<classObj1, classObj2,classObj2>
我有一个class
class C
{
public:
C() {}
private:
int timesTriggered_;
std::map<std::string, std::tuple<std::string, int, int, int, int, int>> mapST;
std::vector<std::string> sv;
};
和一些这种类型的对象:
C c1;
C c2;
C c3;
我有一个由 class C
的字符串索引的地图
std::map<std::string, std::list<C>> cMap;
我将 class C 的一些对象添加到映射中
cMap["1"].push_back(c1);
cMap["2"].push_back(c2);
cMap["3"].push_back(c3);
我需要一个函数,当传递 std::list 时将 return (例如具有三个元素)一个
std::tuple<C&, C&, C&>(c1, c2, c3)
即使这需要 return 和 std::tuple,元组的项目始终是同一类型 C。无论列表中有多少项目,这都必须有效,尽管编译时 C 对象数量的上限是可以的。所以本质上,这将一个列表(元素数量有上限)变成了一个可变元组。
这是一个return我需要的函数:
template <typename... Obs> std::tuple<Obs &...> BindObservers(Obs &... obs)
{
return std::tuple<Obs &...>(obs...);
}
它的名字是这样的:
auto obs2 = BindObservers(c1, c2, c3);
问题是要使用 BindObservers,我需要知道传递给它的参数的数量,逗号之间的东西。我希望有一个像这样工作的 BindObservers:
auto obs2 = BindObservers(std::list<C>);
obs2 看起来像(伪代码):
std::tuple<C,C,more Cs here to the length of std::list<C>>(one parameter for each item in std::list<C> seperated by commas)
所以它是一种模板元编程。
我需要它来使用 c++11,因为我没有 c++14 编译器。
列表在编译时具有不确定数量的元素。
元组在编译时具有已知数量的元素。
因此,编译器无法推断出元组中元素的数量(因为它需要有关列表元素的信息,而这些信息仅在 运行 时间内已知)。
尝试用一个带有一些整数的示例来重新表述一个新问题,以显示您想要实现的目标。
此代码在 clang 和 g++(使用 C++11)上正常工作:
http://coliru.stacked-crooked.com/a/c8071ab447e10a31
生成具有 Max_N
个相同类型元素的 std::tuple
,并用给定列表的第一个值填充它。如果列表中的元素少于 Max_N
,则用标记值填充最后一个元素。
在实践中,如果需要从具有动态数量元素的列表传递到具有恒定数量元素的列表,使用 std::array<C, N>
可能更有用。
#include <tuple>
#include <type_traits>
#include <list>
#include <iostream>
#include <typeinfo>
template<std::size_t Max_N, typename List>
class list_to_tuple {
public:
using value_type = typename List::value_type;
using iterator_type = typename List::const_iterator;
using tuple_type = decltype(std::tuple_cat(
std::tuple<typename List::value_type>(),
typename list_to_tuple<Max_N-1, List>::tuple_type()
));
tuple_type operator()(const List& lst, const value_type& sentinel) {
return convert(lst.begin(), lst.end(), sentinel);
}
tuple_type convert(iterator_type begin, iterator_type end, const value_type& sentinel) const {
list_to_tuple<Max_N-1, List> remaining;
if(begin != end) {
auto current = std::make_tuple(*begin);
++begin;
return std::tuple_cat(current, remaining.convert(begin, end, sentinel));
} else {
return std::tuple_cat(std::make_tuple(sentinel), remaining.convert(begin, end, sentinel));
}
}
};
template<typename List>
class list_to_tuple<0, List> {
public:
using value_type = typename List::value_type;
using iterator_type = typename List::const_iterator;
using tuple_type = std::tuple<>;
tuple_type convert(iterator_type begin, iterator_type end, const value_type& sentinel) const {
return std::tuple<>();
}
};
int main() {
std::list<int> lst = {1, 2, 3};
list_to_tuple<5, std::list<int>> to_tup;
auto tup = to_tup(lst, 0);
std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<1>(tup) << std::endl;
std::cout << std::get<2>(tup) << std::endl;
std::cout << std::get<3>(tup) << std::endl;
std::cout << std::get<4>(tup) << std::endl;
std::cout << typeid(tup).name() << std::endl;
}
根据你的问题,你想要:
auto obs2 = BindObservers(std::list<C>);
obs2 看起来像(伪代码):
std::tuple<C,C,more Cs here to the length of std::list<C>>
(std::list中每一项一个参数,用逗号分隔)
调用 BindObservers
名称(可能是 template
函数)return 的类型必须由其模板参数完全指定。在这种情况下,您没有传递模板参数,但确实传递了 std::list<C>
。 BindObservers
可以从 std::list<C>
.
的类型推导出一些模板参数
推导的类型仅取决于类型std::list<C>
。
这意味着使用两个不同的 std::list<C>
对 BindObservers
的所有调用必须 return 相同的类型。
因为您想要一个包含 1 个元素的列表 return 与包含 2 个元素的列表不同的类型,并且两个不同的类型不是同一类型,所以无法做到这一点。
现在,您总是可以 return 一个大的 std::tuple
房间 "enough" 达到某个限制大小。您还可以获取一个函数对象,并使用最大固定大小的 std::tuple
调用它(每个版本都被实例化,但只调用正确的版本)。
但是你没有问这些可能性,所以答案是"no, your problem cannot be solved"。
我有一个class
class C
{
public:
C() {}
private:
int timesTriggered_;
std::map<std::string, std::tuple<std::string, int, int, int, int, int>> mapST;
std::vector<std::string> sv;
};
和一些这种类型的对象:
C c1;
C c2;
C c3;
我有一个由 class C
的字符串索引的地图std::map<std::string, std::list<C>> cMap;
我将 class C 的一些对象添加到映射中
cMap["1"].push_back(c1);
cMap["2"].push_back(c2);
cMap["3"].push_back(c3);
我需要一个函数,当传递 std::list 时将 return (例如具有三个元素)一个
std::tuple<C&, C&, C&>(c1, c2, c3)
即使这需要 return 和 std::tuple,元组的项目始终是同一类型 C。无论列表中有多少项目,这都必须有效,尽管编译时 C 对象数量的上限是可以的。所以本质上,这将一个列表(元素数量有上限)变成了一个可变元组。
这是一个return我需要的函数:
template <typename... Obs> std::tuple<Obs &...> BindObservers(Obs &... obs)
{
return std::tuple<Obs &...>(obs...);
}
它的名字是这样的:
auto obs2 = BindObservers(c1, c2, c3);
问题是要使用 BindObservers,我需要知道传递给它的参数的数量,逗号之间的东西。我希望有一个像这样工作的 BindObservers:
auto obs2 = BindObservers(std::list<C>);
obs2 看起来像(伪代码):
std::tuple<C,C,more Cs here to the length of std::list<C>>(one parameter for each item in std::list<C> seperated by commas)
所以它是一种模板元编程。
我需要它来使用 c++11,因为我没有 c++14 编译器。
列表在编译时具有不确定数量的元素。
元组在编译时具有已知数量的元素。
因此,编译器无法推断出元组中元素的数量(因为它需要有关列表元素的信息,而这些信息仅在 运行 时间内已知)。
尝试用一个带有一些整数的示例来重新表述一个新问题,以显示您想要实现的目标。
此代码在 clang 和 g++(使用 C++11)上正常工作:
http://coliru.stacked-crooked.com/a/c8071ab447e10a31
生成具有 Max_N
个相同类型元素的 std::tuple
,并用给定列表的第一个值填充它。如果列表中的元素少于 Max_N
,则用标记值填充最后一个元素。
在实践中,如果需要从具有动态数量元素的列表传递到具有恒定数量元素的列表,使用 std::array<C, N>
可能更有用。
#include <tuple>
#include <type_traits>
#include <list>
#include <iostream>
#include <typeinfo>
template<std::size_t Max_N, typename List>
class list_to_tuple {
public:
using value_type = typename List::value_type;
using iterator_type = typename List::const_iterator;
using tuple_type = decltype(std::tuple_cat(
std::tuple<typename List::value_type>(),
typename list_to_tuple<Max_N-1, List>::tuple_type()
));
tuple_type operator()(const List& lst, const value_type& sentinel) {
return convert(lst.begin(), lst.end(), sentinel);
}
tuple_type convert(iterator_type begin, iterator_type end, const value_type& sentinel) const {
list_to_tuple<Max_N-1, List> remaining;
if(begin != end) {
auto current = std::make_tuple(*begin);
++begin;
return std::tuple_cat(current, remaining.convert(begin, end, sentinel));
} else {
return std::tuple_cat(std::make_tuple(sentinel), remaining.convert(begin, end, sentinel));
}
}
};
template<typename List>
class list_to_tuple<0, List> {
public:
using value_type = typename List::value_type;
using iterator_type = typename List::const_iterator;
using tuple_type = std::tuple<>;
tuple_type convert(iterator_type begin, iterator_type end, const value_type& sentinel) const {
return std::tuple<>();
}
};
int main() {
std::list<int> lst = {1, 2, 3};
list_to_tuple<5, std::list<int>> to_tup;
auto tup = to_tup(lst, 0);
std::cout << std::get<0>(tup) << std::endl;
std::cout << std::get<1>(tup) << std::endl;
std::cout << std::get<2>(tup) << std::endl;
std::cout << std::get<3>(tup) << std::endl;
std::cout << std::get<4>(tup) << std::endl;
std::cout << typeid(tup).name() << std::endl;
}
根据你的问题,你想要:
auto obs2 = BindObservers(std::list<C>);
obs2 看起来像(伪代码):
std::tuple<C,C,more Cs here to the length of std::list<C>>
(std::list中每一项一个参数,用逗号分隔)
调用 BindObservers
名称(可能是 template
函数)return 的类型必须由其模板参数完全指定。在这种情况下,您没有传递模板参数,但确实传递了 std::list<C>
。 BindObservers
可以从 std::list<C>
.
推导的类型仅取决于类型std::list<C>
。
这意味着使用两个不同的 std::list<C>
对 BindObservers
的所有调用必须 return 相同的类型。
因为您想要一个包含 1 个元素的列表 return 与包含 2 个元素的列表不同的类型,并且两个不同的类型不是同一类型,所以无法做到这一点。
现在,您总是可以 return 一个大的 std::tuple
房间 "enough" 达到某个限制大小。您还可以获取一个函数对象,并使用最大固定大小的 std::tuple
调用它(每个版本都被实例化,但只调用正确的版本)。
但是你没有问这些可能性,所以答案是"no, your problem cannot be solved"。