如何检查两个元组的所有成员是否不同?

问题描述:

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的任何类型的实现都是可以接受的(使用或不使用我的第一次尝试方法)。

+0

你的意思是检查两个内容元组?我被*弄糊涂了,如果** a **元组的所有成员都不相同,将返回true * – Jonas

+0

@Jonas:检查两个元组的所有成员是否不同。编辑帖子。 – jpo38

+0

Boost.Hana有一个'disjoint'函数来检查元组是否有共同的元素。 – TemplateRex

您可以使用以下:

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

Demo

执行情况的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; 
}