【问题标题】:Ternary operator with std::index_sequence带有 std::index_sequence 的三元运算符
【发布时间】:2015-09-28 12:05:21
【问题描述】:

在以下代码中:

#include <iostream>
#include <utility>
#include <set>

template <typename... Args>
void f(Args... args) {
    std::cout << sizeof...(Args) << " elements.\n";
}

template <std::size_t... Is>
void g (std::index_sequence<Is...>, const std::set<int>& set) {
    f((set.find(Is) == set.end() ? Is : 2*Is)...);
}

int main() {
    g (std::make_index_sequence<10>{}, {1,3,7,8});
}

如果set.find(Is) == set.end(),我希望f((set.find(Is) == set.end() ? Is : 2*Is)...); 使用Is,否则什么都不使用(而不是2*Is)。因此传递的参数数量不是固定的。如何实现?

编辑: 抱歉,我把问题简化得太多了。下面的代码更能反映真正的问题:

#include <iostream>
#include <utility>
#include <tuple>

template <typename... Args>
void f(Args... args) {
    std::cout << sizeof...(Args) << " elements.\n";
}

struct NullObject {};

template <typename Tuple, std::size_t... Is>
void g (std::index_sequence<Is...>, const Tuple& tuple) {
    f ((std::get<Is>(tuple) != std::get<Is+1>(tuple) ? std::get<Is>(tuple) : NullObject{})...);
}

int main() {
    g (std::make_index_sequence<8>{}, std::make_tuple(2,1.5,'a','a',true,5,5,false));
}

由于三元运算符传递的混合类型,上面没有编译,但我想你可以在这里看到我的想法。如果条件为std::get&lt;Is&gt;(tuple) != std::get&lt;Is+1&gt;(tuple),我不想传递任何内容,所以我传递NullObject{},然后以某种方式尝试从f 的参数中删除所有NullObjects,以获得传递给f 的真实参数。

【问题讨论】:

  • 你不能,不是用 三元 表达式。为什么不使用if 语句?或者在三元表达式中调用f函数,而不是在f调用中使用三元表达式。
  • 如果您可以通过编译类型替换您的std::set 内容,您可以执行以下操作:Demo
  • @Jarod42 对不起,我把问题简化得太多了,我更新了问题。我不确定你的技术是否仍然适用。
  • @prestokeys:如果您将(运行时)变量转换为类型(在std::integral_constant 的帮助下),您可以正确调用f,但无论如何它都需要辅助函数。

标签: c++ templates c++11 variadic


【解决方案1】:

您不能为此使用三元运算符 - 这需要两个具有共同类型的表达式。这里没有骰子。我不知道根据 runtime 比较有条件地返回不同的 type 方法。

您必须有条件地将类型转发给不同的函数,只需引入另一个构建 Args... 的辅助函数和一个简单的 if 语句:

template <size_t... Js>
void fhelper (std::index_sequence<>, const std::set<int>& , std::index_sequence<Js...>) {
    f(Js...);
}

template <std::size_t I, size_t... Is, size_t... Js>
void fhelper (std::index_sequence<I, Is...>, const std::set<int>& set, std::index_sequence<Js...>) {
    if (set.find(I) == set.end()) {
        fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js..., I>{});
    }
    else {
        fhelper(std::index_sequence<Is...>{}, set, std::index_sequence<Js...>{});
    }
}

int main() {
    fhelper (std::make_index_sequence<10>{}, {1,3,7,8}, std::index_sequence<>{});
}

【讨论】:

  • @Barry 对不起,我把问题简化得太多了,我更新了问题。我不确定你的技术是否仍然适用。
  • @prestokeys 当然可以,我想只需调用f(std::get&lt;Js&gt;(tuple)...)
  • @Barry 是的,我尝试过并在我的问题中发布了它,但它没有编译(元组元素索引出界错误)。虽然我认为它可以修复。更新:已修复。谢谢。
  • @prestokeys 它无法编译,因为您传入了make_index_sequence&lt;8&gt;{}。您的元组大小为 8,并且您正在比较连续的元素,因此您想传入 make_index_sequence&lt;7&gt;
【解决方案2】:

我只是想分享我所寻求的一般问题的解决方案。巴里对上述特定问题的解决方案使之成为可能:

#include <iostream>
#include <utility>
#include <tuple>

template <template <std::size_t, typename> class Check, typename F, size_t... Js, typename Tuple>
void screenArguments (std::index_sequence<>, std::index_sequence<Js...>, const Tuple& tuple) {
    F()(std::get<Js>(tuple)...);
}

template <template <std::size_t, typename> class Check, typename F, std::size_t I, size_t... Is, size_t... Js, typename Tuple>
void screenArguments (std::index_sequence<I, Is...>, std::index_sequence<Js...>, const Tuple& tuple) {
    if (Check<I, Tuple>::execute(tuple))
        screenArguments<Check, F>(std::index_sequence<Is...>{}, std::index_sequence<Js..., I>{}, tuple);
    else
        screenArguments<Check, F>(std::index_sequence<Is...>{}, std::index_sequence<Js...>{}, tuple);
}

template <template <std::size_t, typename> class Check, typename F, typename Tuple, std::size_t N = std::tuple_size<Tuple>::value>
void passCertainArguments (const Tuple& tuple) {
    screenArguments<Check, F> (std::make_index_sequence<N>{}, std::index_sequence<>{}, tuple);
}

// Testing
#include <typeinfo>

template <typename... Args>
void foo (Args&&...) {
    std::cout << sizeof...(Args) << " elements passed into foo.\n";
}

struct Foo {
    template <typename... Args>
    void operator()(Args&&... args) {
        foo(std::forward<Args>(args)...);
    }
};

template <typename... Args>
void bar (Args&&...) {
    std::cout << sizeof...(Args) << " elements passed into bar.\n";
}

struct Bar {
    template <typename... Args>
    void operator()(Args&&... args) {
        bar(std::forward<Args>(args)...);
    }
};

template <std::size_t N, typename Tuple>
struct CheckArguments {
    static bool execute (const Tuple& tuple) {
        return std::get<N>(tuple) != std::get<N+1>(tuple);
    }
};

struct NullObject {};

template <std::size_t N, typename Tuple>
struct CheckNotNullObject {
    static bool execute (const Tuple& tuple) {
        return typeid(std::get<N>(tuple)) != typeid(NullObject);
    }
};

template <typename F, typename... Args>
void executeWithoutNullObject (Args&&... args) {
    passCertainArguments<CheckNotNullObject, F> (std::forward_as_tuple(args...));
}

template <typename F, typename... Args>
void executeRemoveConsecutiveRepeatElements (Args&&... args) {
    const auto tuple = std::forward_as_tuple(args...);
    passCertainArguments<CheckArguments, F, decltype(tuple), sizeof...(Args) - 1> (tuple);
}

int main() {
    executeWithoutNullObject<Foo> (3, 5, 'a', true, NullObject{}, 'b', 5.8, NullObject{}, NullObject{}, '!', 2);
    // 8 elements passed into foo.  (the 3 NullObjects are removed)
    executeRemoveConsecutiveRepeatElements<Bar> (2, 1.5, 'a', 'a', true, 5, 5, false);
    // 5 elements passed into bar.  (the first 'a', the first 5, and 'false' removed)
}

【讨论】:

    猜你喜欢
    • 2011-09-30
    • 2023-02-03
    • 2016-07-05
    • 2016-02-12
    • 2015-01-22
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2019-07-21
    相关资源
    最近更新 更多