これは過去数時間にわたって私を夢中にさせてくれました。この問題を回避することはできません。私は、これらの60行のコード(メイン関数を含む)にまで問題を絞り込んだ。 別の名前空間とCRTPのテンプレートフレンド機能
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
だから、私が「欲しい」何それは
A<Derived>
の具象サブクラスで呼び出されるたびに、コンパイラは
n1::f
の私の関数テンプレートの特殊化を選択することです。コンパイラーが私の特殊化を支持するためには、すべてのサブクラス(この場合は
B
)に対して、単に呼び出しを委任する
n1::f
のテンプレート特殊化を指定する必要があります。その場合、私は
n1::f
が
A<Derived>
の友人であると宣言しているので、
A<Derived>
のメンバー変数
data
は
n1::f
にアクセスできると考えています。しかし、GCCは
A<Derived>::data
がプライベートでアクセスできないと訴えている。
see this snippet on Coliru。
この構成は可能ですか?もしそうなら、どうすればA<Derived>::data
にアクセスできないと不平を言うコンパイラを回避できますか? (公開することは選択肢ではありません)。
私は見る...これは動作します!ワオ。余分なテンプレートパラメータ 'D'が*必須*である理由を説明できますか?私の友人宣言は、 'A'を友人にすることができるように見えますが、それには別のテンプレートパラメータが必要だと思われます。 –
rwols
@rwols私は詳細を追加しました。それらは異なるテンプレートパラメータリストと異なる引数を持つため、2つの異なる関数テンプレートです。私はそれをよりよく説明する方法を知らない... – skypjack
ありがとう、私はこれが私のために物事をクリアすると思います。 – rwols