8

最小限の例では、少し複雑になり、親テンプレートのパラメータを推定するために乱用です:は、それがクラスのスコープ内の関数をconstexprのためにポインタを渡すときに私が得た

struct A { }; 

template <int> 
struct Parent { }; 

template <int N> 
constexpr int operator*(A, Parent<N>*) { return N; } 

template <class T> 
using ptr = T*; 

template <int> 
struct Other { }; 

template <int N> 
struct Kid: Parent<N> { 
    static Other<A{} * ptr<Kid>{}> o; 
}; 

int main() { 
    Kid<2>{}; 
} 

[gcc][clang]は文句を言い、何の問題もなく、コードをコンパイルします

:私たちは、コードビットを変更したときより不条理取得するには

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid' 
constexpr int operator*(A, Parent<N>*) { return N; } 

Kid問題に対してParentのマッチングについて

struct A { }; 

template <int> 
struct Parent { }; 

template <int N> 
constexpr int operator*(A, Parent<N>*) { return N; } 

template <class T> 
using ptr = T*; 

template <int> 
struct Other { }; 

template <int N> 
struct Kid: Parent<N> { 
    static constexpr int s = A{} * ptr<Kid>{}; 
}; 

int main() { 
    Other<Kid<2>::s>{}; 
} 

[clang]もコードをコンパイルします。だから...バグか、私は狂っていくのですか?

+2

100%の回答では助けになることはできませんが、一般的に 'gcc'は' clang'よりも容認されていますが、後者はもっと厳密に標準に従っています。私はそれがここの場合だと思うでしょう。ただし、インテル®コンパイラーもこのコードを受け入れます。 – davmac

答えて

6

法王は法律上の権利を持っています。はい、KidParentに由来します。しかし、その関係は、Kidが完全に定義されたタイプである場合にのみ確立することができます。よく、[class.mem]/6

クラスは、クラス指定の閉鎖}で完全に定義されたオブジェクトのタイプ([basic.types]) (または完全なタイプ)であると考えられます。クラスメンバー指定の クラス内では、クラスは 関数本体、デフォルト引数、noexcept指定子、およびデフォルトの メンバー初期化子(ネストされたクラス内のものを含む)内の完全とみなされます。 それ以外の場合は、それ自身のクラス メンバ指定内では不完全とみなされます。

私はここで強調している「それ以外の部分」にあります。ポインタを扱っていても、ポインタ変換が有効であるとはまだ定義されていません。 GCCは過度に許容的です。

+1

それは**答え**のように聞こえます:少なくともあなたは私が狂ったと言っていない;)ところで - いい冬の帽子! –

+0

誰もが異議を唱える人がいなければ、私はバグを報告します...もっと短いMCVEを見つけることを望みましょう...;) –

+1

@ W.F。 - 私は誰もこれについてもっと光を当てることができるかどうかを見てみたいと思っています。そして、あなたは言葉のどんなストレッチでも狂気ではないが、その例...;) – StoryTeller

関連する問題