C ++ 11の理解を深めるために、機能的なヘルパーを作成して、それらの呼び出しの冗長性を減らすことができるかどうかを確認しています。現在some
、コレクション内のいずれかのアイテムがテストに合格した場合にtrueを返す関数を作成しようとしています。私はそれがどんなコレクションタイプでも動作し、どんな呼び出し可能でも取ることができ、そしてテンプレート引数を必要としないことを望みます。
基本的に、次のコードがコンパイルされるように機能させたいと思います。
// insert declaration of some here
#include <list>
#include <functional>
class Foo {
public:
bool check() const { return true; };
};
class DerivedFooList : public std::list<Foo> {
public:
DerivedFooList(std::initializer_list<Foo> args) : std::list<Foo>(args) {};
};
class DerivedFooPtrList : public std::list<Foo *> {
public:
DerivedFooPtrList(std::initializer_list<Foo *> args) : std::list<Foo *>(args) {};
};
bool intCheck(int a) { return a == 1; }
bool fooCheck(const Foo &a) { return a.check(); }
bool fooPtrCheck(const Foo *a) { return a->check(); }
int main()
{
Foo a, b, c;
std::list<int> intList = {1, 2, 3};
std::list<Foo> fooList = {a, b, c};
std::list<Foo *> fooPtrList = {&a, &b, &c};
DerivedFooList derivedFooList = {a, b, c};
DerivedFooPtrList derivedFooPtrList = {&a, &b, &c};
auto localIntCheck = [] (int a) { return a == 1; };
auto localFooCheck = [] (const Foo &a) { return a.check(); };
auto localFooPtrCheck = [] (const Foo *a) { return a->check(); };
some(intList, [] (int a) { return a == 1; });
some(intList, &intCheck);
some(intList, localIntCheck);
some(fooList, [] (const Foo &a) { return a.check(); });
some(fooList, &fooCheck);
some(fooList, localFooCheck);
some(fooList, &Foo::check);
some(fooPtrList, [] (const Foo *a) { return a->check(); });
some(fooPtrList, &fooPtrCheck);
some(fooPtrList, localFooPtrCheck);
some(fooPtrList, &Foo::check);
some(derivedFooList, [] (const Foo &a) { return a.check(); });
some(derivedFooList, &fooCheck);
some(derivedFooList, localFooCheck);
some(derivedFooList, &Foo::check);
some(derivedFooPtrList, [] (const Foo *a) { return a->check(); });
some(derivedFooPtrList, &fooPtrCheck);
some(derivedFooPtrList, localFooPtrCheck);
some(derivedFooPtrList, &Foo::check);
return 0;
}
コレクションの値型がオブジェクトまたはオブジェクトポインタである場合、の2番目の引数としてメンバー関数へのポインタを渡せるようにしたいことに注意してくださいsome
。そして、それは物事が毛むくじゃらになるところです。
私の最初の試みは、次のように実装することでした。
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const &t){ return (t.*func)(); });
}
template <template<class, class> class T, class U, class V, class W>
bool some(const T<U *, V> &list, bool (W::*func)() const)
{
return some(list, [=](U const *t){ return (t->*func)(); });
}
...ただし、コレクションがSTLコレクションでない場合、または少なくとも1つが2つのテンプレート引数を取る場合は機能しません。私の例では、を使用するDerivedFooList
か、機能しDerivedFooPtrList
ません。
私の2回目の試みは次のようになりました。
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(const T &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
これはDerivedFooList
現在は機能しますが、std::list<Foo *>
またはでは機能しませんDerivedFooPtrList
。
私の3番目の試みはこれでした:
template <class T, class F>
bool some(const T &list, F &&func)
{
for(auto item : list) {
if (func(item)) {
return true;
}
}
return false;
}
template <class T, class U>
bool some(typename std::enable_if<std::is_class<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const &t) { return (t.*func)(); });
}
template <class T, class U>
bool some(typename std::enable_if<std::is_pointer<typename T::value_type>::value, T>::type const &list, bool (U::*func)() const)
{
return some(list, [=](U const *t) { return (t->*func)(); });
}
とりあえず、これはという名前のメンバーを持つコレクションでのみ機能することを無視value_type
すると、上記の例をコンパイルすることはできません。その理由は、some
使用したい場合の2番目の2つのバージョンのTを推定できないためだと思います(ただし、100%確実ではありません)。
私はC ++ 11から欲しいものを引き出す方法があるかどうかを確認するために一生懸命努力しました、そして私はそれがあると思います、しかし私はそれを理解することができません。私が望むことは可能ですか?もしそうなら、どうすればいいですか?
template<class R, class F>
bool some( R const& r, F&& f ) {
for(auto&& x:r)
if (std::ref(f)(decltype(x)(x)))
return true;
return false;
}
std::ref
概念()
を実行するためのオーバーロードINVOKE
。C++ 17ではstd::invoke
。を介して直接アクセスできます。あなたの要件はINVOKE
コンセプトと一致しているようです。
decltype(x)(x)
が推定変数であるstd::forward
場合、式と同等です。「それが宣言されたタイプであるかのように扱う」と読んでください。が値の場合、とは異なり、コピーされることに注意してください。x
auto&&
x
x
auto
forward
INVOKE( pmf, ptr )
そしてINVOKE( pmf, ref )
両方とも動作します。したがって、過負荷で派手なことをする必要はありません。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加