C ++:メンバー関数へのポインターを含む任意のファンクターを取得できるように、関数をオーバーロードするにはどうすればよいですか?

GuyGizmo

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から欲しいものを引き出す方法があるかどうかを確認するために一生懸命努力しました、そして私はそれがあると思います、しかし私はそれを理解することができません。私が望むことは可能ですか?もしそうなら、どうすればいいですか?

Yakk-Adam Nevraumont
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場合と同等です。それが宣言されたタイプであるかのように扱う」と読んでください値の場合、とは異なり、コピーされることに注意してくださいxauto&&xxautoforward

INVOKE( pmf, ptr )そしてINVOKE( pmf, ref )両方とも動作します。したがって、過負荷で派手なことをする必要はありません。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ