Clangはコードをコンパイルしませんが、gccとmsvcはそれをコンパイルしました


14

何が問題なのか理解できません。コードまたはコンパイラ(可能性が低い)のどちらかです。次のようなコードがあります。

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

GCCとMSVCの両方でコンパイルします。GCCとMSVC 17(ローカル)および19の異なるバージョンを使用して、godboltでテストしました。リンクは次のとおりです:https ://godbolt.org/z/Enfm6L 。

しかし、Clangはそれをコンパイルせず、エラーを出します。

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

そして、私は興味があります-おそらく、このコードの一部が正しくない、またはおそらく何か他の標準の一部があるでしょう。


どのようにしている「のstd ::セット:: reverse_iterator」「のstd ::設定:: dummy_iterator」打ち鳴らすヘッダで定義されていますか?
mvidelgauz

std :: set :: dummy_iteratorはclangヘッダーでまったく定義されていません(私は期待しています)。以下のように問題が定義に含まれていないため、dummy_iteratorは任意の値に変更でき、結果は変更されません。
Andrei

Andreiに感謝します、私は答えを読みました、そしてそれは確かに興味深いです
mvidelgauz

回答:


9

これは、CWG 1558に関連している可能性が非常に高いです。

エイリアステンプレートの特殊化における未使用の引数の扱いは、17.6.7 [temp.alias]の現在の表現では指定されていません。例えば:

  #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がintであるfirst_ofへの参照は単にvoidと同等ですか、それとも置換の失敗ですか?

それは後で対処された欠陥ですが、使用したClangのバージョンがまだ修正を実装していない場合でも、両方の特殊化は2番目の引数を単にとして定義し、void置換の失敗全体を行わないと見なす可能性があります。回避策は、プレーンエイリアスを使用するのではstd::void_tなく、少し複雑なバージョンを使用することです。

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

クラステンプレート(エイリアスが現在意味するもの)の場合、置換の失敗が定義されます。これをサンプルに差し込むと、Clang https://godbolt.org/z/VnkwsMが簡単になります


1
別の回避策は、各要件の特性を作成し、それをenable_ifwith std::disjunction(または
require

ヘルプとリファレンスをありがとう!Clangのこの種のバグについて聞いて悲しいです。おかしいですが、私はvoid_tの実装が標準であると思いました。テンプレートエイリアスのアイデアを採用できません。
Andrei
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.