3

I would like to figure out true / false based on all of elements in std::tuple are same type or not.

for example

std::tuple<int, int, int> t = { 1, 1, 1};
auto A = all_same(t);

std::tuple<int, float, int> t = { 1, 1.0, 1};
auto B = all_same(t);

here, A is true, B is false

anyway to do this?

Aamir
  • 1,974
  • 1
  • 14
  • 18
yi bruce
  • 71
  • 4
  • Why you want `1!=1.0`? Do you know if you try `cout << 1==1.0` you'll get `true`? – Jason Apr 26 '23 at 05:10
  • @273K The duplicate does not answer the question since the conditions are assumed to be independent, in this question they are not. – Quimby Apr 26 '23 at 05:14
  • 1
    @Q `all_of` there is a clear hint of a single condition to all tuple elements, and *whether they all fulfill the above condition*. – 273K Apr 26 '23 at 05:20
  • @273K That is true but I also think there is clear, non-duplicate answer to this searchable-in-the-future question that OP wants and could be simply provided. – Quimby Apr 26 '23 at 05:25

4 Answers4

3

C++17 solution with fold expressions:

#include <tuple>

template<typename Head, typename...Tail>
constexpr bool all_same(const std::tuple<Head,Tail...>&){
    return (std::is_same_v<Head,Tail> && ...);
}

constexpr bool all_same(const std::tuple<>&){
    return true; // This is reasonable, right?
}


int main() {
            std::tuple<int, int, int> t1{ 1, 1, 1};
          static_assert(all_same(t1));

          std::tuple<int, float, int> t2{ 1, 1.0f, 1};
          static_assert(!all_same(t2));
          std::tuple<> t3{};
          static_assert(all_same(t3));
}

Maybe you want to use alternatives/additions to std::is_same_v:

  • std::is_convertible, although you should check both pairs since it is not symetric.
  • std::swappable might be the symetric version of is_convertible in this sense.
  • Adding std::decay if you want const float& and float to be considered equals.
Quimby
  • 17,735
  • 4
  • 35
  • 55
2

The types of the tuple std::tuple<A,B,C,D> are all the same when std::tuple<A,B,C,D> and std::tuple<B,C,D,A> are the same type.

#include <type_traits>
#include <tuple>
#include <iostream>

template <typename First, typename... T>
struct all_same_type {
    constexpr static bool value = std::is_same_v< std::tuple<First,T...>,
                                                  std::tuple<T...,First>>;
};

template <typename... T>
struct all_same_type<std::tuple<T...>> : all_same_type<T...> {};

template <typename... T>
constexpr bool all_same_type_v = all_same_type<T...>::value;

int main() {
    std::tuple<int, int, int> t = { 1, 1, 1};
    std::cout << all_same_type_v< decltype(t)> << "\n";

    std::tuple<int, float, int> u = { 1, 1.0, 1};
    std::cout << all_same_type_v< decltype(u)> << "\n";
}

Output:

1
0
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

Here is a way of doing this using fold expressions and lambda expression:

#include <tuple>
#include <iostream>

//for returning result based on both "type and value"
template<typename First, typename... Rest>
bool allSame(const std::tuple<First, Rest...> &tup ) requires(std::is_same_v<First, Rest> && ...)
{
    return std::apply([](const auto&... nth)
    {
        return (true == ... == nth  );
    }, tup);    
}
//version that always returns false if any type mismatch
template<typename First, typename... Rest>
bool allSame(const std::tuple<First, Rest...> &tup ) requires (... || !std::is_same_v<First, Rest>)
{    
    return false;
}

int main(){
    std::tuple<int, int, int> t = { 1, 1, 1};
    std::cout << allSame(t); //prints 1 

    std::tuple<int, float, int> t2 = { 1, 1.0, 1};
    std::cout << allSame(t2); //prints 0  

    std::tuple<int, int, int> t3 = { 1, 8, 1};
    std::cout << allSame(t3); //prints 0
}

Demo


Note

If you don't care about the values, then it is trivial to replace the body of the first template with return true; as shown in this modified demo

Jason
  • 36,170
  • 5
  • 26
  • 60
  • 1
    I don't think OP cares about the values. Only about types. – HolyBlackCat Apr 26 '23 at 06:31
  • @HolyBlackCat Looking at the code in OP's given question I think they do care about values. Anyways it is **trivial** to just replace the body(the lambda expression part) of the first template with just `return true;` as shown in [this demo](https://godbolt.org/z/ofaKfb6hv). This can be a simple exercise for OP. I've added a note at the end of my answer. – Jason Apr 26 '23 at 06:58
0

Another variant:

template <typename... Ts>
struct all_same_type : std::bool_constant<[](){
        if constexpr (sizeof...(Ts) == 0) {
            return true;
        } else {
            using First = std::tuple_element_t<0, std::tuple<Ts...>>;
            return (std::is_same_v<First, Ts> && ...);
        }
    }()>
{
};

template <typename T>
struct all_same_inner_type;

template <typename... Ts>
struct all_same_inner_type<std::tuple<Ts...>> : all_same_type<Ts...> {};

template <typename...Ts>
constexpr bool all_same_inner_type_v = all_same_inner_type<Ts...>::value;

Demo

Jarod42
  • 203,559
  • 14
  • 181
  • 302