Dentang tidak mengkompilasi kode tetapi gcc dan msvc mengkompilasinya

14

Saya tidak mengerti apa masalahnya: baik dalam kode saya atau di kompiler (kurang mungkin). Ada sepotong kode seperti ini:

#include <iostream>
#include <type_traits>
#include <set>


template<typename T, typename = void>
struct TestA: std::false_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::reverse_iterator>> : std::true_type {};

template<typename T>
struct TestA<T, std::void_t<typename T::dummy_iterator>> : std::true_type {};

int main()
{
    std::cout << TestA<std::set<int>>::value;
}

Baik GCC dan MSVC mengkompilasinya. Saya mengujinya di godbolt dengan versi GCC dan MSVC 17 (lokal) dan 19 yang berbeda. Berikut ini tautannya: https://godbolt.org/z/Enfm6L .

Tapi Dentang tidak mengkompilasi dan memancarkan kesalahan:

redefinition of `'TestA<T, std::void_t<typename T::dummy_iterator> >'`

Dan saya tertarik - mungkin ada beberapa bagian dari standar di mana kode ini tidak benar atau mungkin sesuatu yang lain.

Andrei
sumber
Bagaimana "std :: set :: reverse_iterator" dan "std :: set :: dummy_iterator" didefinisikan dalam header dentang?
mvidelgauz
std :: set :: dummy_iterator tidak didefinisikan di header dentang sama sekali (saya harap). Anda dapat mengubah dummy_iterator ke apa pun yang Anda inginkan dan itu tidak akan mengubah hasilnya karena masalahnya tidak dalam definisi seperti yang terlihat di bawah ini.
Andrei
Terima kasih Andrei, saya membaca jawabannya dan itu memang menarik
mvidelgauz

Jawaban:

9

Ini sangat mungkin terkait dengan CWG 1558 .

Perlakuan argumen yang tidak digunakan dalam spesialisasi templat alias tidak ditentukan oleh kata-kata saat ini dari 17.6.7 [temp.alias]. Sebagai contoh:

  #include <iostream>

  template <class T, class...>
    using first_of = T;

  template <class T>
    first_of<void, typename T::type> f(int)
      { std::cout << "1\n"; }

  template <class T>
    void f(...)
      { std::cout << "2\n"; }

  struct X { typedef void type; };

  int main() {
    f<X>(0);
    f<int>(0);
  }

Apakah referensi ke first_of dengan T menjadi setara dengan hanya membatalkan, atau apakah itu kegagalan substitusi?

Ini adalah cacat yang sejak ditangani, tetapi jika versi Dentang yang Anda gunakan belum mengimplementasikan perbaikan, masih mungkin menganggap kedua spesialisasi hanya dengan mendefinisikan argumen kedua sebagai void, dan tidak melakukan seluruh kesalahan penggantian substitusi. Solusinya adalah untuk tidak menggunakan alias polos std::void_t, melainkan versi yang sedikit lebih kompleks

template <typename...> struct voider { using type = void; };
template <typename... T> using my_void_t = typename voider<T...>::type;

Untuk templat kelas (yang merupakan kepanjangan alias sekarang), kegagalan substitusi didefinisikan. Memasukkannya ke dalam contoh Anda akan membuat Dentang https://godbolt.org/z/VnkwsM .

StoryTeller - Unslander Monica
sumber
1
Solusi lain adalah menciptakan sifat untuk setiap persyaratan, dan kemudian menggabungkannya enable_ifdengan std::disjunction(atau membutuhkan klausa)
AndyG
Terima kasih atas bantuan dan referensi! Sedih mendengar tentang bug semacam ini di Dentang. Lucu, saya pikir implementasi void_t Anda adalah standar. Tidak dapat mengadopsi gagasan alias template.
Andrei