SFINAE, VoidT'yi farklı derleyicilerle kullanmak farklı sonuçlara yol açar


10

Aşağıdaki kodu göz önünde bulundurun:

template <typename T> using VoidT = void;

class A {
public:
   using TEST = int;
};

class C {
public:
   using DIFFERENT = int;
};

template <typename T, typename Enable = void>
class B {
public:
   B() = delete;
};

template <typename T>
class B<T, VoidT<typename T::TEST>> {
public:
   B() = default;
};

template <typename T>
class B<T, VoidT<typename T::DIFFERENT>> {
public:
   B() = default;
};

int main() {
   B<A> a;
   B<C> b;

   return 0;
}

G ++ - 4.8.5 kullanarak, bu kodu derlemek bana aşağıdaki hata iletisini verir:

~/test/compile_test> g++ -std=c++11 test.cpp

test.cpp:31:7: error: redefinition of ‘class B<T, void>’

test.cpp:24:7: error: previous definition of ‘class B<T, void>’

Ancak, g ++ - 8.3 (örneğin, ideone içinde) kullanarak derlediğimde kod derler ve farklı uzmanlıklar doğru davranılır. Bu GCC'de düzeltilen bir hata mıydı, yoksa bir şekilde tanımlanmamış davranışları mı çağırıyorum (ve bu nedenle derleyici davranışındaki fark bir tartışma noktasıdır - tanımsızdır)?

Yanıtlar:


9

Bu GCC'de düzeltilen bir hata mıydı?

Standartta bir kusurdu. Önceki standart sürümler için geriye dönük olarak düzeltildi, ancak elbette sadece daha yeni derleyici sürümleri düzeltilecek. Öyleydi CWG Sayı 1558 ve alıntı ondan:

Takma ad şablonu uzmanlığında kullanılmayan argümanların işlenmesi, ş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?

DR düzeltmesi olmayan derleyiciler için geçici çözüm bir yardımcı kullanmaktır:

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

Sınıf şablonunda değiştirme hatası garanti edilir.


1
Geriye dönük düzeltmeler beni rahatsız ediyor. Bu, dilin herhangi bir sürümünü tanımlayan hiçbir zaman standart bir belge olmadığı anlamına gelir.
Yörüngedeki Hafiflik Yarışları

2
@LightnessRacesinOrbit - Ne demek istediğini anlıyorum. Bu tür geriye dönük düzeltmelerin sadece reddedilmemesi gereken geçerli yapılar için ayrılması umut edilebilir, bu nedenle zarar asgari düzeydedir.
StoryTeller - Unlander Monica

@StoryTeller Gerçekten.
Yörüngedeki Hafiflik Yarışları
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.