Clang kodu derlemez ancak gcc ve msvc derledi


14

Sorunun ne olduğunu anlamıyorum: kodumda veya derleyicide (daha az mümkün). Bunun gibi bir kod parçası var:

#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;
}

Hem GCC hem de MSVC derler. GCC ve MSVC 17 (yerel) ve 19'un farklı versiyonu ile godbolt üzerinde test ettim. İşte bir bağlantı: https://godbolt.org/z/Enfm6L .

Ancak Clang derlemiyor ve bir hata veriyor:

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

Ve ilgileniyorum - belki de bu kod parçasının yanlış olduğu ya da başka bir şeyin olduğu standartların bir kısmı vardır.


Clang başlıklarında "std :: set :: reverse_iterator" ve "std :: set :: dummy_iterator" nasıl tanımlanır?
mvidelgauz

std :: set :: dummy_iterator clang başlıklarında hiç tanımlanmamıştır (umarım). Dummy_iterator öğesini istediğiniz gibi değiştirebilirsiniz ve sorun aşağıda görüldüğü gibi tanımda olmadığından sonucu değiştirmez.
Andrei

Teşekkür ederim Andrei, cevabı okudum ve gerçekten ilginç
mvidelgauz

Yanıtlar:


9

Bu büyük olasılıkla CWG 1558 ile ilgilidir .

Takma ad şablonu uzmanlığında kullanılmayan argümanların tedavisi, şu anki 17.6.7 [temp.alias] ifadesiyle belirtilmemiştir. Örneğin:

  #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);
  }

T'nin first_of değerine int basitçe geçersiz kılınmaya eşdeğer midir yoksa bir ikame hatası mıdır?

O zamandan beri ele alınan bir kusur, ancak kullandığınız Clang sürümü henüz düzeltmeyi uygulamıyorsa, her iki uzmanlığı da ikinci argümanı basitçe tanımlamak voidve tüm ikame hatası spiel'ını yapmamak olarak düşünebilir . Çözüm, düz bir takma ad kullanmak std::void_tyerine biraz daha karmaşık bir sürüm kullanmaktır.

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

Bir sınıf şablonu için (diğer ad şu anda budur), ikame hatası tanımlanır. Bunu örneğinize taktığınızda Clang https://godbolt.org/z/VnkwsM uygular .


1
Başka bir geçici çözüm, her gereksinim için özellikler oluşturmak ve daha sonra bunları bir (veya bir gereksinim cümlesi) enable_ifile birleştirmek olacaktırstd::disjunction
AndyG

Yardım ve referans için teşekkür ederiz! Clang'daki bu tür böcekleri duymak üzücü. Komik olsa da, void_t uygulamasının standart olduğunu düşündüm. Şablon yumuşatma fikrini kabul edemiyorum.
Andrei
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.