如何检查两个元组的所有成员是否不同?
问题描述:
std::tuple<...>::operator!=
如果至少返回true one两个比较元组的成员不同。如何检查两个元组的所有成员是否不同?
我需要的,如果两相对比所有元组的成员是不同的,将返回true的功能:
template <class... Args>
bool areAllMembersDifferent(const std::tuple<Args...>& left, const std::tuple<Args...>& right)
{
bool allDiff = true;
// iterate through the tuples are set allDiff to false if one member's is different than other's
return allDiff;
}
从我在网上找到的启发,我写的是这样(改编功能打印元组内容):
template <std::size_t N, std::size_t, class = make_index_sequence<N>>
struct CheckTupleLoop;
template <std::size_t N, std::size_t J, std::size_t... Is>
struct CheckTupleLoop<N, J, index_sequence<Is...>> {
template <class Tup>
int operator()(bool& allDiff, const Tup &left,const Tup &right) {
if (std::get<J>(left) == std::get<J>(right))
allDiff = false;
return 0;
}
};
template <class... Args>
bool areAllMembersDifferent(const std::tuple<Args...>& left, const std::tuple<Args...>& right)
{
bool allDiff = true;
CheckTupleLoop<sizeof...(Args)>{}(allDiff,left,right);
return allDiff;
}
但是,这显然是不正确的,因为编译器报告我Error C2955 'CheckTupleLoop': use of class template requires template argument list
C++ 11中的bool areAllMembersDifferent
的任何类型的实现都是可以接受的(使用或不使用我的第一次尝试方法)。
答
您可以使用以下:
namespace detail
{
template <std::size_t ... Is, typename Tuple>
bool areAllMembersDifferent(std::index_sequence<Is...>,
const Tuple& left,
const Tuple& right)
{
bool res = true;
const int dummy[] = {0, (res &= std::get<Is>(left) != std::get<Is>(right), 0)...};
static_cast<void>(dummy); // Avoid warning for unused variable
return res;
}
}
template <typename Tuple>
bool areAllMembersDifferent(const Tuple&left, const Tuple& right)
{
return detail::areAllMembersDifferent(
std::make_index_sequence<std::tuple_size<Tuple>::value>(), left, right);
}
执行情况的std::make_index_sequence
C++ 11(这是C++ 14)可以很容易地
发现在C++中17,你甚至可以简化辅助功能:
namespace detail
{
template <std::size_t ... Is, typename Tuple>
bool areAllMembersDifferent(std::index_sequence<Is...>,
const Tuple& left,
const Tuple& right)
{
return (std::get<Is>(left) != std::get<Is>(right) && ...);
}
}
+0
工程太棒了!谢谢。希望有一天,我将能够写出这种类型的代码而不要求这样做...... ;-) – jpo38
答
你可以使用下面的C++ 11标准的解决方案,以达到你所需要的:
template <size_t N>
struct CompareTuples
{
template<class... Args>
static bool areAllMembersDifferent(const std::tuple<Args...>& left, const std::tuple<Args...>& right)
{
return (std::get<N>(left) != std::get<N>(right)) && CompareTuples<N-1>::areAllMembersDifferent(left, right);
}
};
template<>
struct CompareTuples<0>
{
template<class... Args>
static bool areAllMembersDifferent(const std::tuple<Args...>& left, const std::tuple<Args...>& right)
{
return (std::get<0>(left) != std::get<0>(right));
}
};
template<class... Args>
bool areAllMembersDifferent(const std::tuple<Args...>& left, const std::tuple<Args...>& right)
{
return CompareTuples<std::tuple_size<std::tuple<Args...>>::value-1>::areAllMembersDifferent(left, right);
}
答
Jarod42的答案是比较合理的,但这里是我的2美分:
#include <iostream>
#include <tuple>
#include <limits>
template <size_t index>
struct next_index
{
static const size_t value = index - 1;
};
template <>
struct next_index<0>
{
static const size_t value = 0;
};
template <class Tuple, size_t index>
bool is_same(const Tuple& left, const Tuple& right)
{
if (index != 0)
return is_same<Tuple, next_index<index>::value>(left, right) and std::get<index>(left) != std::get<index>(right);
return std::get<index>(left) != std::get<index>(right);
}
template <typename Tuple>
bool areAllMembersDifferent(const Tuple& left, const Tuple& right)
{
return is_same<Tuple, std::tuple_size<Tuple>::value - 1>(left, right);
}
int main() {
std::cout << areAllMembersDifferent(std::make_tuple(12, '*', 4.2f), std::make_tuple(11, '#', 4.25f)) << std::endl;
std::cout << areAllMembersDifferent(std::make_tuple(12, '*', 4.2f), std::make_tuple(11, '#', 4.2f)) << std::endl;
}
你的意思是检查两个内容元组?我被*弄糊涂了,如果** a **元组的所有成员都不相同,将返回true * – Jonas
@Jonas:检查两个元组的所有成员是否不同。编辑帖子。 – jpo38
Boost.Hana有一个'disjoint'函数来检查元组是否有共同的元素。 – TemplateRex