2016-11-23 1 views
7

std::tuple<...>::operator!= возвращает 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

Любой вид реализации bool areAllMembersDifferent в C++ 11 был бы приемлемым (с использованием или не с моей первой попытки).

+0

ли вы имеете в виду, чтобы проверить содержание двух кортежи? Я запутался в *, вернул бы true, если все члены ** ** кортежа отличаются друг от друга * – Jonas

+0

@Jonas: Проверьте, не отличаются ли все члены двух кортежей. Отредактировано сообщение. – jpo38

+0

Boost.Hana имеет функцию «disjoint», которая проверяет, имеют ли кортежи общие элементы. – TemplateRex

ответ

5

Вы можете использовать следующее:

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

реализации для C++ 11 std::make_index_sequence (который является 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

Отлично работает! Благодарю. Надеюсь, в один прекрасный день я смогу написать такой код, не спрашивая SO .... ;-) – jpo38

2

Вы могут использовать следующие совместимые решения 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); 
} 
0

ответ 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; 
} 
Смежные вопросы