🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

6回答

904閲覧

C++で部分適用的な書き方は出来ますか?

DangerousWayTo

総合スコア5

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

1グッド

1クリップ

投稿2019/10/05 05:29

編集2019/10/05 05:34

昔ながらのプログラミング言語で新しい考え方を取り入れられないかを考えています。
部分適用的なことをC++で出来ないかを考えてみました。
まず、C#で試みました。

C#

1using System; 2 3class Part{ 4 int X; 5 int _add(int y){ 6 return X+y; 7 } 8 public Func<int,int>add(int x){ 9 X=x; 10 return _add; 11 } 12} 13 14class MainClass { 15 static void Main() { 16 17 Part part1=new Part(); 18 Part part2=new Part(); 19 20 Func<int,int>p1=part1.add(10); 21 Func<int,int>p2=part2.add(100); 22 23 Console.WriteLine(p1(1000)); 24 Console.WriteLine(p2(10000)); 25 } 26}

とりあえず、動作はしました。
これと同じ手法でC++でやってみました。

C++

1#include<stdio.h> 2typedef int(*t_add)(int); 3 4class Part{ 5 int X; 6 int _add(int y){ 7 return X+y; 8 } 9 public:t_add add(int x){ 10 X=x; 11 return _add; // コンパイルエラー 12 } 13}; 14 15int main(){ 16 17 Part *part1=new Part(); 18 Part *part2=new Part(); 19 20 t_add p1=part1->add(10); 21 t_add p2=part2->add(100); 22 23 printf("%d\n",p1(1000)); 24 printf("%d\n",p2(10000)); 25 26 return 0; 27}

11行目でコンパイルエラーが発生しましたが、型を合わせる方法が分かりませんでした。
うまく、型を合わせるか、それが無理なら別の方法で解決したいのですが、アドバイスをお願いします。

fa11enprince👍を押しています

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答6

0

現在の C++ のライブラリには部分適用のための std::bind という関数が用意されています。 これを用いれば部分適用したい関数 (クラス) に特別な機能を用意しておかなくてもよく、より汎用性のあるコードに出来ます。

質問中のコードを書き換えるとするとこう書けます。

cpp

1#include <functional> 2#include <iostream> 3 4int main(void){ 5 auto part1 = std::plus<int>(); 6 auto part2 = std::plus<int>(); 7 8 using namespace std::placeholders; 9 auto p1 = std::bind(part1, 10, _1); 10 auto p2 = std::bind(part2, 100, _1); 11 12 std::cout << p1(1000) << std::endl; 13 std::cout << p2(10000) << std::endl; 14 15 return 0; 16} 17

投稿2019/10/05 12:38

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

こんにちは。

C++では、関数は容易に取り扱えますが非staticなメンバー関数の取り扱いは面倒です。
メンバー変数と関数ポインタの2つをハンドリングしないと行けないため、取り扱い辛いのです。

しかし、ファンクターなら、オブジェクトへのポインタだけハンドリングすれば良く取り扱いが簡単ですので、このようなケースではファンクターを使うとスムーズに記述できます。

サンプルです。(メモリ・リークがどうも気持ち悪いのでmain()関数も修正していますが、元のmain()関数でも動きます。)

C++

1#include<stdio.h> 2#include<functional> 3 4class t_add 5{ 6 int X; 7public: 8 t_add(int x) : X(x) { } 9 int operator()(int y) 10 { 11 return X+y; 12 } 13}; 14 15class Part{ 16 public:t_add add(int x){ 17 return t_add(x); 18 } 19}; 20 21int main(){ 22 23 Part part1; 24 Part part2; 25 26 t_add p1=part1.add(10); 27 t_add p2=part2.add(100); 28 29 printf("%d\n",p1(1000)); 30 printf("%d\n",p2(10000)); 31 32 return 0; 33}

wandbox

見ての通り、本当はPartで実装したいことをt_addでやってますので、実は下記でも同じように機能します。

t_add p3(10);
printf("%d\n",p3(1000));

以前、カリー化の質問で部分適用するC++コードを書いてます。テンプレートとラムダ式を同時に使っているので分かりにくいとは思いますが、参考になるかも知れません。

投稿2019/10/05 06:04

編集2019/10/05 06:06
Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ラムダ式を使うと良いかと思います。

C++

1#include <iostream> 2 3int main(void) { 4 auto p1 = [x=10](int y) { return x + y; }; 5 auto p2 = [x=100](int y) { return x + y; }; 6 7 std::cout << p1(1000) << "\n" 8 << p2(10000) << "\n"; 9}

投稿2019/10/05 05:41

LouiS0616

総合スコア35668

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

みなさん、御教授頂きありがとうございます。
C言語では出来ないものかも考えてみました。
カリー化は無理のようですが、部分適用のような感じには、出来るようです。

C

1#include<stdlib.h> 2#include<stdio.h> 3 4#define F(f,p,x)p->f(p,x) 5 6typedef int T; 7typedef T(*t_add)(void*,T); 8typedef t_add(*t__add)(void*,T); 9 10typedef struct part{ 11 T X; 12 t_add _add; 13 t__add add; 14}*Part; 15 16T _add(Part p,T y){ 17 return p->X+y; 18} 19t_add add(Part p,T x){ 20 p->X=x; 21 return(t_add)_add; 22} 23 24Part new_Part(){ 25 Part p=(Part)malloc(sizeof(struct part)); 26 p->_add=(t_add)_add; 27 p->add=(t__add)add; 28 return p; 29} 30 31int main(){ 32 33 Part part1=new_Part(); 34 Part part2=new_Part(); 35 36 t_add p1=F(add,part1,10); 37 #define P1(x)p1(part1,x) 38 39 t_add p2=F(add,part2,100); 40 #define P2(x)p2(part2,x) 41 42 printf("%d\n",P1(1000)); 43 printf("%d\n",P2(10000)); 44 45 free(part1); 46 free(part2); 47 48 return 0; 49}

投稿2019/10/05 13:02

編集2019/10/19 06:08
DangerousWayTo

総合スコア5

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

回答にならないかもですが、
C++11以降なら std::function だったかな。
それが提供されています。

ヒント1: cppreference.com

これを使えば行けそう...ですかね。

あと、モダンなC++でやるなら、typedefじゃなくて using のほうがいいらしいです。
ヒント2: C++11ではtypedefはオワコン

また、(私は使い慣れていないですが) 生ポインタは使わずに、いわゆるスマポ(スマートポインタ)と言われる、weak_ptr とか shared_ptr 等を使うのが主流のようです。
ヒント3: スマートポインタを使ってみる - std::shared_ptr - - 大雨のち大晴れ

つまり、C++11以降 (C++11, C++14, C++17 ... ) として使えば可能な場合がありますね。

投稿2019/10/05 05:46

BeatStar

総合スコア4962

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

第57章 メンバ関数ポインタ天国 this の分を忘れているからだと思います。

投稿2019/10/05 05:41

Zuishin

総合スコア28669

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問