Saya mencoba mencari cara untuk melakukan beberapa hal yang tampaknya sulit bagi saya sehubungan dengan konsep dan tipe templat seperti std::vector.

  1. Saya mencoba menerapkan batasan waktu kompilasi yang mirip dengan cara saya menggunakan std::movable pada T, tetapi pada C dengan PushBackMovable. Ini berfungsi dengan persyaratan di ujung belakang fungsi decl, tetapi saya ingin konsisten dan menempatkan batasan saya di dalam args templat. Saya mencoba mengganti "kelas C" dengan "PushBackMovable C", tetapi itu tidak terlalu gagal, tetapi lebih dekat dengan apa yang saya inginkan.

  2. Saya mencoba menggunakan jenis template dalam parameter templated template.
    2a. Apakah ada cara untuk mendeklarasikan C dan menggunakan argumen templat di dalamnya di dalam tanda tangan fungsi? Misalnya, dapatkah saya menghapus "T" dan "Alloc", dan menggunakan "_T" dan "_Alloc"? Kelihatannya bahwa saya tidak dapat mengakses parameter tersebut. Saya ingin menghemat ruang kode.
    2b. Apakah cara mereka untuk menghapus <> kosong pada C pada argumen pertama operator?
    2c. Kompiler dapat menyimpulkan jenis templat C pada persyaratan jika saya baru saja PushBackMovable, tapi kemudian declval barf. Apakah ada trik yang saya lewatkan untuk menentukan template secara implisit? parameter, khususnya pada instance "C"? Akan lebih baik untuk hanya mengatakan "C".

  3. Apakah cara mereka lebih mudah untuk memeriksa keberadaan metode daripada di bawah ini?

Berikut adalah contoh kode saya untuk kedua kasus:

#include <vector>
#include <type_traits>
#include <algorithm>

template<typename T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C >
concept PushBackMovable = std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(std::move(T{}))),void> &&
                          std::is_same_v<decltype(std::declval<C<T,Alloc> >().push_back(T{})),void>; 

template<std::movable T, typename Alloc, template<typename _T=T, typename _Alloc=Alloc> class C > 
void operator+=( C<>& lhs, T rhs ) requires PushBackMovable<T, Alloc, C>
{
  lhs.push_back( std::forward<T>( rhs ) );
}

int main() {
  std::vector<int> ints;
  int a = 5;

  ints += 1;
  ints += a;

  std::copy(std::begin(ints), std::end(ints), std::ostream_iterator<int>(std::cout, " "));
}

Terima kasih untuk bantuannya.

0
mriera 25 Mei 2020, 11:35

1 menjawab

Jawaban Terbaik

Dengan menggunakan parameter template-template, Anda sudah membatasi fungsi Anda ke container yang mengikuti pola library standar tetapi juga ke template kelas yang kebetulan memiliki dua parameter template tipe. Ini adalah batasan yang kuat dan biasanya tidak berguna dalam praktik. Artinya, saya menyarankan agar Anda mengoperasikan tipe konkret yang diwakili oleh parameter templat tipe, dan biarkan konsep memverifikasi persyaratan apa pun yang ingin Anda terapkan.

Selain itu, jangan gunakan decltype dengan std::declval dengan std::is_same untuk memeriksa validitas ekspresi. Konsep memiliki sintaks khusus untuk tujuan itu, yang hanya menempatkan ekspresi ini dalam kurung kurawal.

Salah satu solusi, menggabungkan apa yang ingin Anda verifikasi dalam satu konsep, bisa seperti di bawah ini:

#include <concepts>
#include <utility>
#include <type_traits>

template <typename C, typename T>
concept PushBackMovable = requires (C c, T t) {
    { c.push_back(t) } -> std::same_as<void>;
    { c.push_back(std::move(t)) } -> std::same_as<void>;
};

template <typename T, PushBackMovable<std::remove_reference_t<T>> C>
void operator+=(C& lhs, T&& rhs)
{
    lhs.push_back(std::forward<T>(rhs));
}

DEMO

1
Piotr Skotnicki 25 Mei 2020, 10:09