Tは `std :: declval <T>`で使用される完全な型である必要がありますか?


11

この例を見てみましょう(ここから来ます):

#include <type_traits>
#include <iostream>
template <typename U>
struct A {
};

struct B {
   template <typename F = int>
   A<F> f() { return A<F>{}; }

   using default_return_type = decltype(std::declval<B>().f());
};

int main()
{
    B::default_return_type x{};
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
}

それはgcc9.2でエラーなしコンパイルしますが、gcc7.2とclang 10.0.0 Bは完了していないことについて不平を言います。Clangsエラーは:

prog.cc:11:58: error: member access into incomplete type 'B'
   using default_return_type = decltype(std::declval<B>().f());
                                                         ^
prog.cc:7:8: note: definition of 'B' is not complete until the closing '}'
struct B {
       ^
prog.cc:16:8: error: no type named 'default_return_type' in 'B'
    B::default_return_type x{};
    ~~~^
prog.cc:17:35: error: no member named 'default_return_type' in 'B'
    std::cout << std::is_same< B::default_return_type, A<int>>::value;
                               ~~~^

1
質問のタイトルがエラーと一致していないようですか?私にとって、GCCはについて不満を持っているよう.f()です。それは理にかなっている; 不完全な型にBはメンバーがありませんf
MSalters

@MSalters私は同じことを考えましたが、ここで本当の問題は何ですか?std::declval型が完全であるかどうかにかかわらず、インスタンスを取得したら、それは問題にならないと思います(そして、私はそれが間違っていると思います)
idclev 463035818

[expr.ref] / 2(C ++ 11)はクラスメンバーのアクセスについて次のように述べています。またB、完全ではありませんalias-declaration
Language


1
@LanguageLawyer了解しました。私の解釈が正しくなかったことに同意します。c++ 11以降に何かが変更されたように思われます。答えを書いていただけませんか。
idclev 463035818

回答:


9

エラーの原因はではなくstd::declval、不完全なクラスメンバーアクセスです。

CWG1836 の解決 2.5年前にマージれるまで、この規格では、クラスがクラスメンバーアクセス式で完全であることを要求していました(E1.E2)。
[expr.ref] / 2 in C ++ 11

最初のオプション(ドット)の場合、最初の式は完全なクラス型でなければなりません。

[expr.ref] / 2 in C ++ 17

最初のオプション(ドット)の場合、最初の式は完全なクラス型を持つglvalueです。

また、クラスはクラスalias-declaration内で完全であるとは見なされませんmember-specification
[class.mem] / 6 in C ++ 17

クラスは}class-specifierの終了時に完全に定義されたオブジェクトタイプ([basic.types])(または完全なタイプ)と見なされます。クラスmember-specification内では、クラスは関数本体、デフォルト引数、noexcept-specifier、およびデフォルトメンバー初期化子(ネストされたクラスなど)内で完全であると見なされます。それ以外の場合は、独自のクラスメンバー仕様内では不完全と見なされます。


8

[declval]から:

備考:のテンプレートパラメータTdeclval不完全な型である可能性があります。

この表現はC ++ 11以降に存在しています(そのため、コンパイラが以前の標準に準拠することはできません)


すごい、それが私が望んでいたことです。gccで修正されたようですが、clangは(まだ)修正されていません
idclev 463035818

@ formerlyknownas_463035818:私が最初に考えたのはT、完全な型であるべきだということでした。規格を確認できて良かったです。
AndyG
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.