按值比较可变参数

时间:2017-09-24 15:09:10

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

有没有办法比较每种类型的可变参数模板的值?

template<typename... S>
class Signature {
    // this is not valid syntax
    S... values;

    bool equals(S... s) {
        // this is not either
        bool eq = true;
        eq &= s... &= values...;
        return eq;
    }
};

示例:

Signature<int, bool> s(5, true);
s.equals(5, true); // should result in 1

3 个答案:

答案 0 :(得分:4)

此:

S... values;

是不正确的。你不能有这样的包装声明(不幸的是)。您必须将所有值放在某些内容中,例如:

std::tuple<S...> values;

一旦你这样做,比较它们很简单。只需使用==

template<typename... S>
struct Signature {
    std::tuple<S...> values;

    bool equals(Signature<S...> const& rhs) const {
        return values == rhs.values;
    }

    bool equals(S const&... rhs) const {
        // forward here to produce a tuple<S const&...> and avoid an unnecessary copy
        return values == std::forward_as_tuple(rhs...);
    }
};

答案 1 :(得分:2)

我们只需:

std::tuple<S...> values;
bool equals(S const&...s) const {
  return std::apply([&](S const&... values){
    return ((values==s)&&...);
  }, values);
}

由于S... values;不合法。

中,最好的方法是编写自己的apply

namespace details{
  template<std::size_t...Is, class F, class Tuple>
  decltype(auto) apply(std::index_sequence<Is...>, F&& f, Tuple&&t){
    using std::get;
    return std::forward<F>(f)( get<Is>( std::forward<Tuple>(t) )... );
  }
}
template<class F, class Tuple>
decltype(auto) apply( F&& f, Tuple&& tuple )
  using dT=std::decay_t<Tuple>;
  auto size=std::tuple_size<dT>{};
  return details::apply( std::make_index_sequence<size>{}, std::forward<F>(f), std::forward<Tuple>(tuple) );
}

并将其放入namespace notstd。你还需要放置折叠:

return ((values==s)&&...);

bool r = true;
using discard=int[];
(void)discard{0,(void(
  r = r && (values==s)
),0)...};
return r;

中,您需要将decltype(auto)替换为尾随返回类型,并实现自己的索引序列代码。

答案 2 :(得分:1)

我能看到的真正问题是......什么是

std::tuple
你班上的

据我所知,这不是C ++。

我想您可以将值保存在std::tuple<S...> value;

s

所以(如果你不想把你的std::tuple放在#include <tuple> #include <utility> #include <iostream> template <typename ... Ts> struct Signature { std::tuple<Ts...> values; Signature (Ts && ... ts) : values { std::forward<Ts>(ts) ... } { } template <std::size_t ... Is> bool equalsH (std::index_sequence<Is...> const &, Ts const & ... ts) { return ((ts == std::get<Is>(values)) && ... ); } bool equals (Ts const & ... ts) { return equalsH(std::make_index_sequence<sizeof...(Ts)>{}, ts...); } }; int main () { Signature<int, bool> s { 5, true }; std::cout << s.equals(5, true) << std::endl; // print 1 std::cout << s.equals(5, false) << std::endl; // print 0 std::cout << s.equals(6, false) << std::endl; // print 0 std::cout << s.equals(6, true) << std::endl; // print 0 } 并比较元组,这很简单但不好笑)你的代码中的真正问题与使用有关元组。

基于新的折叠表达式

,我在C ++ 17中提出了以下解决方案
equalH()

在C ++ 14中,你不能像在C ++ 17中那样使用fold表达式,所以你必须修改辅助函数( template <std::size_t ... Is> bool equalsH (std::index_sequence<Is...> const &, Ts const & ... ts) { using unused = int[]; bool ret { true }; (void)unused { 0, (void(ret &= (ts == std::get<Is>(values))), 0) ... }; return ret; } );我建议如下

std::make_index_sequence

不幸的是std::index_sequencestd::make_index_sequence仅从C ++ 14开始可用,因此前面的示例在C ++ 11中不起作用;但是创建std::index_sequencebool equals (Ts && ... ts) { return values == std::forward_as_tuple( std::forward<Ts>(ts) ... ); } 的替代并不困难,如果你想要它,你可以使用元组比较解决方案

help(RLdata500)