引数の型が構造内で定義された型から派生するフレンド関数を使用して、テンプレート化された構造を定義したいと考えています。対応する構造体がインスタンス化されている場合、フレンド関数は明示的な型指定なしで呼び出すことができます。
次のアプローチが機能しているようです。
template <typename T> struct A {
typedef T const& underlying_param_type;
typedef A<T>& param_type;
friend void mutateA(param_type a, underlying_param_type b) { a.data_ = b; }
T data_;
};
構造体の内部構造に依存しないパラメーター型でフレンド関数を定義すると、次のようにインターフェースと実装を分離することができます。
template <typename T> struct B;
template <typename T> void mutateB(B<T>& a, T const& b);
template <typename T> struct B {
friend void mutateB <> (B<T>& a, T const& b);
T data_;
};
template <typename T> void mutateB(B<T>& a, T const& b) { a.data_ = b; }
現在、両方のアプローチを組み合わせることができるかどうか疑問に思っています。次のアプローチは機能しません (clang++ 3.3、g++ 4.8.2、-std=c++11):
template <typename T> struct C;
template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b);
template <typename T> struct C {
typedef T const& underlying_param_type;
typedef C<T>& param_type;
friend void mutateC <> (typename C<T>::param_type a, typename C<T>::underlying_param_type b);
T data_;
};
template <typename T> void mutateC(typename C<T>::param_type a, typename C<T>::underlying_param_type b) { a.data_ = b; }
int main() {
A<int> a;
mutateA(a, 1);
B<int> b;
mutateB(b, 1);
C<int> c; // error: no function template matches function template specialization 'mutateC'
mutateC(c, 1);
return 0;
}
テンプレート引数の推定が ::. で機能しないため、最後のアプローチは失敗すると思います。何か案は?