次のコードスニペットを検討してください。
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; ^~~~~~~~~~~~~~
両方の実装が標準に準拠していますか?
そうでない場合、どの実装がここで正しいのですか、そしてなぜですか?
C++ 17の[variant.visit] はvariant_size_v
を使用しませんが、- 現在の草案 では---の結果として使用します 社説変更 。 LWGが変更を導入する前にレビューしたという兆候は見られませんが、それ以来、規格のこの部分を何度か検討しており、まだ反対していません。そのため、事実が必要です。
一方、LEWGで言及されている LWG問題3052 には、明示的にstd::variant
が必要です。その問題が解決されると-いずれかの方法で-これも解決するはずです。
Gcc実装のバグのようです。 cppreference によると、std::get
でinvoke
を呼び出すのと同じように呼び出されます。 std::get<>
は、std::variant
に変換可能なものに対して定義されます(参照を転送することでstd::variant
引数を受け入れるため)。構造はstd::variant
に変換できるため、std::get
自体はgccの構造で機能します。
Gcc実装がvisit
の実装の一部としてstd::variant_size
を使用することを選択したという事実は、それらの実装の詳細であり、構造体では機能しない(そして機能してはならない)という事実です。無関係です。
結論:実装の見落としのため、gccのバグです。