休眠コードはgcc4.7で動作します。アイデアは、シーケンス、ポインター、タプル、ペア、ユーザー定義型などで機能するこれらの総称関数を持っているということです。これらの関数の1つが型に対して定義されている場合、すべてが定義されている必要があります。私が抱えている問題は、それらをどのように専門化するかを決定することです。タイプごとに特化したテンプレートクラスを定義し、各関数を実装してから、クラス内の実装に転送するだけの無料の関数を定義することにしました。
#include <utility>
#include <vector>
#include <iterator>
#include <memory>
#include <iostream>
#include <algorithm>
using namespace std;
template< class M > struct Mon;
template< class X, class F,
class M = Mon< typename decay<X>::type > >
auto mon( X&& x, F f ) -> decltype( M::mon(declval<X>(),f) ) {
return M::mon( forward<X>(x), f );
}
template< class C > struct IsSeqImpl {
// Can only be supported on STL-like sequence types, not pointers.
template< class _C > static true_type f(typename _C::iterator*);
template< class _C > static false_type f(...);
typedef decltype( f<C>(0) ) type;
};
template< class C > struct IsSeq : public IsSeqImpl<C>::type { };
/* Enable if is an STL-like sequence. */
template< class C, class R > struct ESeq : std::enable_if<IsSeq<C>::value,R> { };
template< class Seq >
struct Mon : ESeq< Seq, Seq >::type
{
template< class S, class F >
static S mon( const S& s, F f ) {
S r;
transform( begin(s), end(s), back_inserter(r), f );
return r;
}
};
template< class P > struct IsPtrImpl {
template< class X > static true_type f( X );
template< class X > static false_type f( ... );
typedef decltype( f(*declval<P>()) ) type;
};
template< class P > struct IsPtr : public IsPtrImpl<P>::type { };
template< class P, class R > struct EPtr : enable_if<IsPtr<P>::value,R> { };
template< class X > struct Mon< X* >
{
template< class F, class R = decltype( declval<F>()(declval<X>()) ) >
static unique_ptr<R> mon( X* x, F f ) {
typedef unique_ptr<R> U;
return x ? U( new R(f(*x)) ) : U(nullptr);
}
};
int add_one( int x ) { return x + 1; }
int main()
{
vector<int> v = {1,2,3,4,5};
int x = 5;
auto v2 = mon( v, add_one );
auto x2 = mon( &x, add_one );
// Should print 2 and 6.
cout << v2[0] << '\n';
cout << *x2 << '\n';
}
私がやりたいのは、より一般的な型にMonを特化することですが、enable_if継承トリックを再度使用しようとすると、gccはMonがすでに定義されていると文句を言います。この質問で述べたように、2番目のテンプレート引数をSFINAEのtrue_またはfalse_typeにする手法も試しましたが、コンパイルすることができませんでした。
理想的には、アクションを定義したいタイプのカテゴリを考えるときはいつでも、enable_ifを記述して、関数のグループ全体をテンプレートの特殊化に記述できる必要があります。これにより、関数ごとに1つのenable_ifを作成する手間が省けます。悲観的に、私は本当に一般的であるために、各カテゴリーのすべてのもっともらしいタイプのためにグループを専門化する必要があるでしょう。
これを一般的で拡張可能な方法で書くことはできますか?
PS:コンセプトだけがC++11の一部だったとしたら。