質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.12%

C++ 関数の引数に関数を渡せますか?

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 722

opyon

score 987

解決!

回答くださった方ありがとうございました。
どの回答もとても参考になりました。
具体的なコードもあったので分かりやすかったです。

実際頻繁に使うのか?と言われると可読性や冗長になることもあるのでなんとも言えませんが、
マクロで出来ないことが実現しやすいし出来ることの可能性はかなり広がったと思います。

サンプルコード(早速使ってみた)

#include <bits/stdc++.h>

bool is_odd(int x)
{
    return x % 2;
}

unsigned fibo(unsigned n)
{
    if (n < 2)
    {
        return 1;
    }
    return fibo(n - 1) + fibo(n - 2);
}

template <typename T1, typename T2, typename Func1, typename Func2, typename T3>
void yn(const T1 &e1, const T2 &e2, const Func1 func1, const Func2 func2, const T3 &fe1)
{
    auto ret1 = func2(fe1);
    auto ret2 = (func1(ret1) ? e1 : e2);
    std::cout << "ret1:" << ret1 << " ret2:" << ret2 << "\n";
}

// 上記では出力するために分けていますが入れ子でも使えますし
// 可変長でも使えそうです
// ret = (func1(func2(fe1)) ? e1 : e2);

int main()
{
    // フィボナッチ数列のi項の奇数偶数判定
    for (unsigned i = 0; i < 20; i++)
    {
        std::cout << "i:" << i << " ";
        yn("odd", "even", is_odd, fibo, i);
    }
    getchar();
    return 0;
}

// 出力サンプル
// i:0 ret1:1 ret2:odd
// i:1 ret1:1 ret2:odd
// i:2 ret1:2 ret2:even
// i:3 ret1:3 ret2:odd
// i:4 ret1:5 ret2:odd
// i:5 ret1:8 ret2:even
// i:6 ret1:13 ret2:odd
// i:7 ret1:21 ret2:odd
// i:8 ret1:34 ret2:even
// i:9 ret1:55 ret2:odd

追記

lambda式を引数として受け取る関数の自作はできますか?
こちらの回答が参考になりそうです。
また時間のある時に作ってみます。

知りたいこと

関数の引数に関数を渡せますか?

現状

前の質問の@LouiS0616さんの回答 で頂いたコードをヒントにこんなこと出来ると便利そうだなと思い質問させていただいています。

例えばこの func1(e1) を引数も指定して渡せたら汎用的に使えて便利そうです。
分かりにくいかも知れませんが例えば func1()func2() を指定して切り替えられますか?
yn(func1(3), "yes", "no");
yn(func2(2), "yes", "no");
例えが悪いのでこれだと結果が渡されて期待通りの結果が出ますがイメージが伝わればと思います。

どのようにしたら出来るのか検討もつかないので出来るか出来ないかだけでもご教示頂けると幸いです。

#include <bits/stdc++.h>

bool func1(int x)
{
    return x % 2;
}

bool func2(int x)
{
    return (x + 1) % 2;
}

template <typename T1, typename T2, typename T3>
void yn(const T1 &e1, const T2 &e2, const T3 &e3)
{
    auto ret = (func1(e1) ? e2 : e3);
    std::cout << ret << "\n";
}

int main()
{
    yn(3, "yes", "no");
    getchar();
    return 0;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+4

こんにちは。

std::bindを使う方法もありますよ。引数の数が異なっても使えます。

#include <iostream>
#include <functional>

bool func1(int x)
{
    return x % 2;
}

bool func2(int x)
{
    return (x + 1) % 2;
}

bool func3(int x, int y)
{
    return (x + y) % 2;
}

template <typename T1, typename T2, typename T3>
void yn(const T1 &e1, const T2 &e2, const T3 &e3)
{
    auto ret = (e1() ? e2 : e3);
    std::cout << ret << "\n";
}

int main()
{
    yn(std::bind(func1, 3), "yes", "no");
    yn(std::bind(func2, 2), "yes", "no");
    yn(std::bind(func3, 2, 3), "yes", "no");
    getchar();
    return 0;
}

引数の順序を変える必要がありますが、可変長引数テンプレートにする手もあります。

#include <iostream>
#include <functional>

bool func1(int x)
{
    return x % 2;
}

bool func2(int x)
{
    return (x + 1) % 2;
}

bool func3(int x, int y)
{
    return (x + y) % 2;
}

template <typename T2, typename T3, typename Func, typename... T1>
void yn(const T2 &e2, const T3 &e3, Func func, T1... e1)
{
    auto ret = (func(e1...) ? e2 : e3);
    std::cout << ret << "\n";
}

int main()
{
    yn("yes", "no", func1, 3);
    yn("yes", "no", func2, 2);
    yn("yes", "no", func3, 2, 3);
    getchar();
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/12 16:59

    回答ありがとうございます。
    std::bindもシンプルに書けそうで良いですね。
    具体的なコードがイメージしてた通りでとても分かりやすく参考になりました。

    キャンセル

+1

できます。
例としては std::qsort は 大小比較関数を引数にわたすようになってます。

https://ja.cppreference.com/w/cpp/algorithm/qsort

参考

追記:
偶数/奇数判定関数を作成し、それを関数の渡すような例を作成してみました。
g.cpp

#include <iostream>

typedef bool (FUNC)(int);

bool is_even(int x) {
  return x % 2;
}

bool is_odd(int x) {
  return (x + 1) % 2;
}

void yn(FUNC func, const int x, std::string s_ok, std::string s_ng) {
  std::string ret = func(x) ? s_ok : s_ng;
  std::cout << ret << "\n";
}

int main() {
  yn(is_even, 1, "yes", "no");
  yn(is_odd, 1, "yes", "no");
  return 0;
}

実行例:
イメージ説明

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/12 07:25

    回答ありがとうございます。
    なるほど確かにsort関連で使ったことがありました。
    汎用的な関数を自作するならどうすればいいのか模索中です。

    キャンセル

+1

引数一つ増やせば出来るんじゃないかなぁ。デフォルトの関数を設定する方法の説明は割愛しますが。

#include <bits/stdc++.h>

bool func1(int x) { return x % 2; }

bool func2(int x) { return (x + 1) % 2; }

struct functor {
    bool operator()(int x) const { return x % 2; };
};

template <typename T1, typename T2, typename T3, typename Func>
void yn(const T1 &e1, const T2 &e2, const T3 &e3, const Func &func) {
    auto ret = (func(e1) ? e2 : e3);
    std::cout << ret << "\n";
}

int main() {
    yn(3, "yes", "no", func1);
    yn(3, "yes", "no", func2);

    // 関数オブジェクト
    yn(3, "yes", "no", functor());

    // lambda式
    yn(3, "yes", "no", [](int x) -> bool { return x % 2; });

    getchar();
    return 0;
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/11/12 16:56

    回答ありがとうございます。
    operator()やlambda式などの書き方もあることを知りとても参考になりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる