SFINAE: optimization of function templates

I would like to somehow iterate over a tuple using member function templates (to later create a new type of tuple from this type of template T).

However, the interrupt condition (function) is not used, so I get this error:

Invalid use of an incomplete type: 'class std :: tuple_element <0ul, std :: tuple <→'

The problem is that even if a N == sizetuple is std::tuple_element_tevaluated for N != sizeand is not treated as SFINAE.

Both examples show different broken solutions. What am I wrong?

Note. The function to evaluate with is is_sameomitted to minimize the example.

#include <type_traits>
#include <tuple>

template<typename...Ts>
struct A
{
  using tuple = std::tuple<Ts...>;
  static constexpr std::size_t size = sizeof...(Ts);

  template<typename T, std::size_t N = 0, typename std::enable_if_t<N == size>* = nullptr>
  int get()
  {
    return 0;
  }

  template<typename T, std::size_t N = 0, typename std::enable_if_t<N != size && !std::is_same<T, std::tuple_element_t<N, tuple>>::value>* = nullptr>
  int get()
  {
    return get<T, N + 1>() - 1;
  }
};

int main()
{
  A<int, float, double, float, float> a;

  return a.get<char>();
}

Live example 1

#include <type_traits>
#include <tuple>

template<typename...Ts>
struct A
{
  using tuple = std::tuple<Ts...>;
  static constexpr std::size_t size = sizeof...(Ts);

  template<typename T, std::size_t N = 0>
  std::enable_if_t<N == size, int> get()
  {
    return 0;
  }

  template<typename T, std::size_t N = 0>
  std::enable_if_t<N != size && !std::is_same<T, std::tuple_element_t<N, tuple>>::value, int> get()
  {
    return get<T, N + 1>() - 1;
  }
};

int main()
{
  A<int, float, double, float, float> a;

  return a.get<char>();
}

Live 2 example

sizeof tuple-2 - 1, ?

#include <type_traits>
#include <tuple>

template<typename...Ts>
  struct A
  {
    using tuple = std::tuple<Ts...>;
    static constexpr std::size_t size = sizeof...(Ts);

    template<typename T, std::size_t N = 0, typename std::enable_if_t<(N == size - 1) && std::is_same<T, std::tuple_element_t<N, tuple>>::value>* = nullptr>
      int get()
    {
      return 1;
    }

    template<typename T, std::size_t N = 0, typename std::enable_if_t<(N == size - 1) && !std::is_same<T, std::tuple_element_t<N, tuple>>::value>* = nullptr>
      int get()
    {
      return 2;
    }

    template<typename T, std::size_t N = 0, typename std::enable_if_t<(N < size - 1) && !std::is_same<T, std::tuple_element_t<N, tuple>>::value>* = nullptr>
      int get()
    {
      return get<T, N + 1>() - 1;
    }
  };

int main()
{
  A<int, float, double, float, float> a;

  return a.get<char>();
}

Live Example 3

+4
3

OP:

, , - ( int ). .

, , , . , - sfinae. , .
, , , , .

:

#include <type_traits>
#include <tuple>

template<typename>
struct tag {};

template<typename...>
struct B;

template<typename T, typename... Ts>
struct B<T, Ts...>: B<Ts...> {
    using B<Ts...>::get;

    auto get(tag<T>) {
        return T{};
    }
};

template<>
struct B<> {
    template<typename T>
    auto get(tag<T>) {
        return nullptr;
    }
};

template<typename...Ts>
struct A: private B<Ts...>
{
    template<typename T>
    auto get() {
        return B<Ts...>::get(tag<T>{});
    }
};

int main()
{
  A<int, float, double, float, float> a;
  static_assert(std::is_same<decltype(a.get<char>()), std::nullptr_t>::value, "!");
  static_assert(std::is_same<decltype(a.get<float>()), float>::value, "!");
}
+1

@PiotrSkotnicki , :

#include <type_traits>
#include <tuple>

template<typename...Ts>
struct A
{
  using tuple = std::tuple<Ts...>;
  static constexpr std::size_t size = sizeof...(Ts);

  template<typename T, std::size_t N = 0>
  std::enable_if_t<N == size-1, int>
  get()
  {
    return std::is_same<T, std::tuple_element_t<N, tuple>>::value ? N : 0;
  }

  template<typename T, std::size_t N = 0>
  std::enable_if_t<N != size-1 && !std::is_same<T, std::tuple_element_t<N, tuple>>::value, int>
  get()
  {
    return get<T, N + 1>() - 1;
  }
};

int main()
{
  A<int, float, double, float, float> a;
  return a.get<char>();
}

?
:

std::enable_if_t<N != size && !std::is_same<T, std::tuple_element_t<N, tuple>>::value, int> get() 

N , enable_if, N == size ( , , N == size ).
, tuple_element_t ( ) .

, size, N. size-1 .

+4

, std::tuple_element_t?

, -

  template <typename T, std::size_t N>
  struct checkType
   { constexpr static bool value
      = std::is_same<T, std::tuple_element_t<N, tuple>>::value; };

  template <typename T>
  struct checkType<T, size>
   { constexpr static bool value = false; };

  template <typename, std::size_t N = 0>
  std::enable_if_t<N == size, int> get ()
   { return 0; }

  template <typename T, std::size_t N = 0>
  std::enable_if_t<(N < size) && ! checkType<T, N>::value, int> get()
   { return get<T, N + 1>() - 1; }
+1

Source: https://habr.com/ru/post/1654588/


All Articles