web-dev-qa-db-ja.com

C ++で関数を引数として渡す

私はC++で少し錆びていて、Pythonの1年後に切り替えています。当然、pythonから来る怠惰をC++に変換したいと思います。

私はrot13を発見したばかりで、とても興奮しています。私はそれを行う3つの方法を見つけ、少しパフォーマンステストをしたいと思いました。所定の位置にある文字列を変更することと、新しい文字列を作成することに違いがあるかどうかも確認したかったのです。だから私は6つの機能を持つことになりました。

最初のメソッドでは、std :: mapを使用して文字をマップします。したがって、マップを初期化するクラスを作成し、2番目のメソッドでは三項演算子を使用し、3番目のメソッドではビットシフトを使用します。

これで、関数のプロトタイプは次のようになります。

// map dependent
void Rot13::convert_inplace(string& mystr){

string Rot13::convert(const string& mystr){

// ternary operator
void bitrot_inplace(string& mystr){

string bitrot(const string&  mystr){

// bit shift
void bitshiftrot_inplace(string& mystr){

string bitshiftrot(const string& mystr){

それらの関数を引数として受け入れる関数を作成して、時間を計算し、結果を出力したかったのです。

だから私はstackoverflow、 12 を見て、これを思いついた

typedef void (*vfc)(string str);

void printtime_inplace(string title, vfc func){

私はこの構造を試しましたが、これはvfcの戻り値の型によって制限されていることを意味します。私の場合はvoidまたはstringのいずれかであり、事実により、クラスのポインタ。したがって、異なる関数に対応するために、クラスメンバー関数の関数、void戻り値の型の関数、文字列の戻り値の型の関数の3つの関数を実行する必要があります。

だから私は自分自身に尋ねました、これは私が本当に同じ関数を3回書かないためにテンプレートを使用する必要がある場合ですか?私は本当にテンプレートに自信がありませんが、3 typedefsを実行して、テンプレートを受け入れるようにprinttime関数を構造化する必要がありますか?さらに、これらのタイプ(つまり、私が定義したタイプ)のみを受け入れるようにテンプレートに指示する方法はありますか?

別の質問ですが、これは良いデザインだとしましょう。または他のデザインを提案しますか?他の実装?

5
Pella86

最も簡単な方法であるIMOは、具体的な型で関数を作成する代わりに、テンプレートを使用することです。

template<typename Function>
void printtime_inplace(string title, Function func)
{
    //...
    func(title);
    //...
}

これにより、「関数」であるものをすべて取得できるようになります。通常の関数、ファンクター、ラムダ、std::function、基本的には任意の呼び出し可能関数を渡すことができます。コンパイラーはさまざまなインスタンス化をスタンプしますが、コードに関する限り、同じ関数を呼び出しています。

8
NathanOliver

std::function そのようなテンプレートを提供するには:

#include <iostream>
#include <functional>
#include <string>
#include <type_traits>

void convert_inplace(std::string& mystr){}
std::string convert(const std::string& mystr){
    return mystr;
}
void bitrot_inplace(std::string& mystr){}

template<typename ret, typename par>
using fn = std::function<ret(par)>;

template<typename ret, typename par>
void caller(fn<ret,par> f) {
    typename std::remove_reference<par>::type p;
    ret r = f(p);
}

template<typename par>
void caller(fn<void,par> f) {
    typename std::remove_reference<par>::type p;
    f(p);
}

int main() {
    auto f1 = fn<void,std::string&>(convert_inplace);
    auto f2 = fn<std::string,const std::string&>(convert);
    auto f3 = fn<void,std::string&>(bitrot_inplace);
    caller(f1);
    caller(f2);
    caller(f3);
    return 0;
}

ライブデモ を参照してください。

5
user0042