【问题标题】:Turning a BOUNDED std::list<class> of parameters into a type std::tuple<class,class,class> tup<classObj1, classObj2,classObj2>将 BOUNDED std::list<class> 参数转换为 std::tuple<class,class,class> tup<classObj1, classObj2,classObj2> 类型
【发布时间】:2015-04-22 15:27:23
【问题描述】:

我有课

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;

我有一张由 C 类字符串索引的地图

std::map<std::string, std::list<C>> cMap;

我将一些 C 类的对象添加到地图中

cMap["1"].push_back(c1);
cMap["2"].push_back(c2);
cMap["3"].push_back(c3);

我需要一个函数,当通过 std::list 时将返回(例如三个元素)一个

std::tuple<C&, C&, C&>(c1, c2, c3)

尽管这需要返回一个 std::tuple,但元组的项目总是相同的类型,C。无论列表中有多少项目,这都必须工作,尽管编译时的 C 对象数量很好。所以本质上这将一个列表(元素数量的上限)变成了一个可变元组。

这是一个返回我需要的函数:

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 编译器。

【问题讨论】:

  • 你今天没有问过类似的问题吗?您收到的 cmets 仍然持有
  • cmets 不能在电脑上运行,还是说不可能?
  • Snark 也不获取答案。 list 中的元素数量是否有界?在一般情况下,您所要求的是不可能的。这怎么不是你的last question的副本?
  • 在一般情况下是不可能的,因为在编译时必须知道要从此函数返回的tuple(也决定了它的类型)中的元素数量,而list 只能在运行时确定。如果列表大小是有界的(你现在说不是),说最大 N 个元素,然后创建一个函数,返回具有 N 个元素的 tuple,如果 list 中的元素较少,则放置一些哨兵在空白处输入(标记可能是具有特殊值的C 的实例)。
  • @Ivan C++ 不懂英文,你要求std::tuple&lt;C...&gt; 作为返回类型。您的函数必须为一组给定的参数类型返回 一个 类型。 您希望它返回哪种类型?这几乎没有意义,您最好回答“您真正想做什么?”的问题。

标签: c++ c++11 tuples variadic-templates template-meta-programming


【解决方案1】:

一个列表在编译时具有不确定数量的元素。

元组在编译时具有已知数量的元素。

因此,编译器无法推断元组中的元素数量(因为它需要有关列表元素的信息,而这些信息仅在运行时才知道)。

尝试用带有一些整数的示例来重新表述一个新问题,以显示您想要达到的目标。

【讨论】:

  • 我想要实现的内容在原帖中的“这是一个返回我需要的函数:”下给出:
  • ‘auto’需要在编译时解析为一个类型。为了推断出您需要从其他一些编译时已知信息中派生的类型,例如另一种已知类型或已知数量的参数。
【解决方案2】:

根据你的问题,你想要:

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 函数)的调用返回的类型必须完全由其模板参数指定。在这种情况下,您不传递模板参数,但传递了std::list&lt;C&gt;BindObservers 可以从std::list&lt;C&gt; 的类型中推导出一些模板参数。

推导的类型仅取决于类型std::list&lt;C&gt;

这意味着使用两个不同的std::list&lt;C&gt;BindObservers 的所有调用都必须返回相同的类型。

由于您希望 1 个元素的列表与 2 个元素的列表返回不同的类型,并且两种不同的类型不是同一类型,因此无法做到这一点。

现在,您始终可以返回一个大的std::tuple,其中包含“足够”的空间,直到某个限制大小。您还可以获取一个函数对象,并使用最大固定大小的std::tuple 调用它(每个版本都被实例化,但只调用正确的版本)。

但你没有问这些可能性,所以答案是“不,你的问题无法解决”。

【讨论】:

    【解决方案3】:

    此代码在 clang 和 g++ 上正常工作(使用 C++11):

    http://coliru.stacked-crooked.com/a/c8071ab447e10a31

    使用相同类型的Max_N 元素生成std::tuple,并用给定列表的第一个值填充它。如果列表中的元素少于Max_N,则用标记值填充最后一个元素。

    在实践中,如果需要从具有动态数量元素的列表传递到具有恒定数量元素的列表,则使用 std::array&lt;C, N&gt; 可能更有用。

    #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;
    }
    

    【讨论】:

    • 谢谢。让我看看是否可以安装 c++14 编译器。希望有一个 c++11 版本...
    • “可能有用”。如果有一个工具可以验证代码是否可以正常编译...
    • 1.这是无法挽救的,2. 这是你的
    • 快到了!如果我替换 std::list lst = {1, 2, 3};与 std::list = {c1, c2, c3}; //见原帖 list_to_tuple> to_tup;我收到错误:调用不匹配 '(list_to_tuple >) (std::list&, int)' 注意:参数 2 没有从 'int' 到的已知转换'const value_type& {aka const C&}'
    • 0 中的to_tup(lst, 0) 也需要是C 类型的标记值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-10
    • 2021-08-05
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2013-05-14
    相关资源
    最近更新 更多