web-dev-qa-db-ja.com

std :: variantから継承するクラスでのstd :: visitの使用-libstdc ++とlibc ++

次のコードスニペットを検討してください。

struct v : std::variant<int, std::vector<v>> { };

int main()
{
    std::visit([](auto){ }, v{0});
}
  • clang ++ 7 with -stdlib=libc++ -std=c++2aはコードをコンパイルします。

  • -std=c++2aを指定したg ++ 9は、コードのコンパイルに失敗し、次のエラーが発生します。

    /opt/compiler-Explorer/gcc-trunk-20180711/include/c++/9.0.0/variant:94:29:error:incomplete type 'std :: variant_size' used innested name specifier

     inline constexpr size_t variant_size_v = variant_size<_Variant>::value;
    
                             ^~~~~~~~~~~~~~
    

godbolt.orgの実例


  • 両方の実装が標準に準拠していますか?

  • そうでない場合、どの実装がここで正しいのですか、そしてなぜですか?

21
Vittorio Romeo

C++ 17の[variant.visit]variant_size_vを使用しませんが、- 現在の草案 では---の結果として使用します 社説変更 。 LWGが変更を導入する前にレビューしたという兆候は見られませんが、それ以来、規格のこの部分を何度か検討しており、まだ反対していません。そのため、事実が必要です。

一方、LEWGで言及されている LWG問題3052 には、明示的にstd::variantが必要です。その問題が解決されると-いずれかの方法で-これも解決するはずです。

12
T.C.

Gcc実装のバグのようです。 cppreference によると、std::getinvokeを呼び出すのと同じように呼び出されます。 std::get<>は、std::variantに変換可能なものに対して定義されます(参照を転送することでstd::variant引数を受け入れるため)。構造はstd::variantに変換できるため、std::get自体はgccの構造で機能します。

Gcc実装がvisitの実装の一部としてstd::variant_sizeを使用することを選択したという事実は、それらの実装の詳細であり、構造体では機能しない(そして機能してはならない)という事実です。無関係です。

結論:実装の見落としのため、gccのバグです。

9
SergeyA