Saya telah melihat jawaban pada SO yang menjelaskan mengapa SFINAE tidak bekerja dengan tipe pengembalian lambda. Saya mengubah desain saya sedikit, tetapi sekarang menerima kesalahan yang lebih aneh. Saya tidak tahu apa yang saya lewatkan. Kode akan dikompilasi dengan C++11, 14 dan 17. Saya memiliki apply yang kompatibel dengan C++17.

#include <algorithm>
#include <vector>
#include <functional>
#include <tuple>
#include <utility>

template <typename ...T>
struct S {
  std::vector<std::tuple<T...>> things;
  template <typename F>
  typename std::enable_if<std::is_same<
    typename std::invoke_result<
      std::apply<F, T...>, F, T...>::type, bool>::value,
      bool>::type
  find_if(const F &f) {
      return std::any_of(things.begin(), things.end(),
      [&](const std::tuple<T...> &t) {
          return std::apply(f, t);
      });
  }
  template <typename F>
  auto find_if(const F &f) -> decltype(std::declval<F>()(things.front())) {
      return std::any_of(things.begin(), things.end(),
      [&](const std::tuple<T...> &t) { return f(t); });
  }
};

void f() {
    S<int, float> s;
    auto l = [](const std::tuple<int, float> &) -> bool { return false; };
    s.find_if(l);
}

Tujuan saya adalah untuk memanggil predikat yang tepat. Jika predikat memiliki satu parameter tipe std::tuple<Ts...>, maka panggil secara langsung. Jika daftar parameter predikat cocok dengan paket parameter templat yang belum dibongkar, panggil yang itu.

Baik GCC dan Dentang mengeluh tentang metode pertama, di mana apply bukan tipe.

<source>:13:26: error: type/value mismatch at argument 1 in template parameter list for 'template<class _Functor, class ... _ArgTypes> struct std::invoke_result'
   13 |       std::apply, F, T...>::type, bool>::value,
      |                          ^
<source>:13:26: note:   expected a type, got 'std::apply'
0
user1150609 13 Agustus 2019, 16:28

1 menjawab

Jawaban Terbaik

Metafungsi std::invoke_result mengharapkan sebagai parameter pertama jenis sesuatu yang dapat dipanggil, dan jenis argumen.

Sayangnya, std::apply bukan tipe, melainkan fungsi. Juga, std::apply dibuat untuk menggunakan pengurangan tipe, jadi tidak ramah sfinae.

Solusinya adalah dengan menggunakan jenis yang dapat dipanggil alih-alih panggilan untuk melamar.

template <typename ...T>
struct S {
    std::vector<std::tuple<T...>> things;

    template <typename F, typename std::enable_if_t<
        std::is_same_v<std::invoke_result_t<F, T...>, bool>, int> = 0>
    auto find_if(const F &f) -> bool {
        return std::any_of(things.begin(), things.end(),
        [&](const std::tuple<T...> &t) {
            return std::apply(f, t);
        });
    }
};

Juga, lambda Anda akan terlihat seperti ini:

[](int, float) -> bool { return false; };

Ini karena apply sedang menguraikan Tuple.

1
Guillaume Racicot 13 Agustus 2019, 13:48