1

の特定のネストされたクラスの非会員の一般的な機能を実装:は、私は以下のクラスを持つクラステンプレート

template<int P> 
struct A { 
    struct B { 
     auto abs() const { return 1; } 
    }; 
}; 

具体AはPを法整数の有限体であるはず、とBが表すクラスですこの有限体からの要素次に、私はabs関数を使うはずの拡張GCDアルゴリズムの汎用実装を持っています。問題は、拡張型GCDアルゴリズムの実装で、基本型(int、longなど)と同様にA<P>::Bで動作するようにしたいという問題です。だから私はA<P>::B::absを呼び出す非会員absを実装する必要があります。私は3つのテクニックを試してみましたが、そのうち2つはうまくいかず、もう1つは適切です。

テクニック1(動作しません):引数依存ルックアップ(ADL)を使用します。 Aのボディ内部が、Bの体外以下を定義します。

auto abs(B const &e) { return e.abs(); } 

ADLがクラススコープではなく名前空間内のみになりますので、それは動作しません。 UPDATEabsがインスタンスメソッドであるため、ADLはここでは機能しません。しかし、T.C.の答えによれば、それを友人の機能にすると正しく動作し、ADLはそれを見つけます!

技術2(動作しない):グローバルまたは名前空間スコープで制約関数テンプレートを使用します。

template<int P> 
auto abs(typename A<P>::B const &e) { return e.abs(); } 

Pが非推定されるコンテキストにあるので、これはまた、動作しません。

テクニック3(作品が、満足のいくものではない):グローバルまたは名前空間スコープで制約のない関数テンプレートを使用します。

template<typename T> 
auto abs(T const &e) { return e.abs(); } 

これは動作します。しかし、それは拘束されていない。この関数テンプレートのインスタンス化は、A<P>(あらかじめわかっているのはP)と他のクラステンプレート(多項式リングとフィールド拡張用)のみに制限したいと考えています。問題は、Pが推論されていないコンテキストにある場合、SFINAEの使用方法がわかりません。

答えて

3
template<int P> 
struct A { 
    struct B { 
     auto abs() const { return 1; } 
    }; 
    friend auto abs(B const &e) { return e.abs(); } 
// ^^^^^^ 
}; 

次に、ADLにその魔法を働かせます。

B内側に定義も結構です。あなたに選択のアップ。)

+0

は、別のソースファイルで、クラスの外に実装し、それが宣言を維持しますが、提供する方法はありますか? –

+1

@ M.Alaggan No.これらは、テンプレート以外の関数のファミリにインスタンス化します。クラステンプレート定義の外にそれを記述する方法はありません。 –

0

これは動作します:

namespace impl { 
    template <int P> 
    struct B { 
     auto abs() const { return 1; } 
    }; 

    template <int P> 
    auto abs(B<P>& b) { 
     return b.abs(); 
    } 
} 

template <int P> 
struct A { 
    using B = impl::B<P>; 
    friend B; 
}; 

int main() { 
    A<3>::B inner; 
    abs(inner); 
} 

Bと同じ名前空間になりましたabsので、このソリューションは、ADLを使用しています。さらに、Bにテンプレートパラメータを再び渡すことによって、Pを推測されないコンテキスト(Pが一部の::シンボルの左側にない)にすることを回避しました。残念ながら、BAのメンバーではありません。もしAのメンバーにアクセスしたいのであれば、あなたは友人になる必要があります。この以前の解決策はthis answerに起因しています。次はそれを改善します。

あなたは本当にBAの一員になりたい場合はまた、あなたが必要とするすべてが正しいリダイレクトを確保するための公共ファサードです:

namespace impl { 
    template <typename T> 
    struct facade : public T {}; 

    template <typename T> 
    auto abs(facade<T>& b) { return b.abs(); } 
} 

template <int P> 
struct A { 
    struct B_ { 
     auto abs() const { return 1; } 
    }; 

    using B = impl::facade<B_ >; 
}; 

int main() { 
    A<3>::B inner; 
    abs(inner); 
} 

ここでの利点は、このパブリックファサードは、再利用可能なであるということですいくつかのクラス、それは友人である必要はありません。

関連する問題