0

私は C++ の学習に取り組んでいますが、メソッドを別のメソッドのパラメーターとして渡すことができるかどうか疑問に思っていましたか?

私がやりたかったことの大まかな概要は次のようなものです:

void insertionSort() {
   //perform sort
}

int timeOfOperation(methodInQuestion) {
    // time 1
    methodInQuestion;
    //time 2
    return time2-time;
}

int main() {
   cout << timeOfOperation(insertionSort());
   return 0;
}

このようなことをする方法はありますか?

編集:

返信ありがとうございます。別の質問があります。私の実際のコードでは、これはすべて dataStructure というクラスで行われており、別の場所でそのインスタンスを作成してこれらのメソッドを呼び出しています。

dataStructure ds();
ds.timeOperation(ds.insertionSort());

投稿されたソリューションのいくつかを実装しようとすると、次のエラーが発生します。

IntelliSense: no instance of function template
"dataStructure::timeOperation" matches the argument list argument
types are: (void) object type is: dataStructure

インスタンスの作成がこれに影響する理由がよくわかりません。誰でも説明できますか?

================================================== ===========

編集2:

この部分の正確なコードを多かれ少なかれ投稿します。

//main.cpp

#include "arrayList.h"
#include "arrayListStructure.h"
#include "Person.h"

using namespace std;

int main() {

    arrayList<Person> *al = new arrayList<Person>(length);
    arrayListStructure als(al);
    //als.fillStructure(data);
    als.timeOperation(als.insertionSort());

return 0;
}


//arrayListStructure.cpp

#include "arrayListStructure.h"
#include <functional>

double arrayListStructure::timeOperation(std::function<void()> operation) {...}
void arrayListStructure::insertionSort() {...}

arrayListStructure::arrayListStructure(arrayList<Person> *al)
{
this -> al = al;
}

もっとありますが、これが問題に関連するすべてだと思います

4

3 に答える 3

2

関数ポインターの使用方法のデモンストレーション


デモ:

#include <iostream>
using namespace std;
 
void insertionSort() {
   cout<<"insertion"<<endl;
}
 
int timeOfOperation(void(*sortFunc)(void)) {
   sortFunc();
   return 1;
}
 
int main() {
   cout << timeOfOperation(insertionSort);
   return 0;
}

このデモを参照してください。

于 2013-02-04T19:27:21.850 に答える
2

はい、次のようなものです:

#include <functional>
#include <ctime>
#include <iostream>

void insertionSort() { /*...*/ }

std::clock_t timeOfOperation( std::function<void()> operation ) 
{
    const std::clock_t start = std::clock();
    operation();
    return std::clock() - start;
}

int main() 
{
    std::cout << timeOfOperation(insertionSort) << '\n';
}

グローバル データ (insertionSort のようなパラメーターのない関数が必要とする) はおそらく必要ないので、次のようにすることができます。

template<class Container>
void insertionSort( Container& c ) 
{ 
   /*sort the contents of c*/ 
}

次に、並べ替えるデータを渡す必要があります。これは、std::bind またはより優れた C++11 ラムダで行うことができます。次に、Yakk の回答に記載されているように、タイマー関数をテンプレート化して、std::関数、ラムダ、ファンクター (operator() がオーバーロードされたクラス)、または関数ポインターをネイティブに受け入れることができます。

template<class Operation>
std::clock_t timeOfOperation( Operation&& operation ) 
{/*...*/ }

完全なプログラムは次のとおりです。

#include <functional>
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm> // for generate
#include <ctime> // for clock
#include <cstdlib> // for rand

template<class Container>
void insertionSort( Container& c ) 
{ 
   /*sort the contents of c*/ 
}

template<class Operation>
std::clock_t timeOfOperation( Operation&& operation ) // or just timeOfOperation( Operation&& operation )
{
    const std::clock_t start = std::clock();
    operation();
    return std::clock() - start;
}

int main() 
{
    std::vector<int> v( 100 );
    std::generate( v.begin(), v.end(), std::rand );
    auto op = [&]() { insertionSort( v ); };
    std::cout << timeOfOperation( op ) << '\n';
}

最後の 2 行 (C++11 ラムダを使用) を次のように結合します。

std::cout << timeOfOperation( [&]() { insertionSort( v ); } ) << '\n';

しかしもちろん、宿題以外のコードでは、独自のソート機能を使用するのではなく、組み込みのソート機能を使用する必要があります。


あなたの更新について:最初の行は実際には関数定義であり、クラスのインスタンス化ではありません:

dataStructure ds(); // function, not an instance!
ds.timeOperation(ds.insertionSort()); // insertionSort returns void. 
// Can't convert void to a template param that can be called with the () operator

C++ のルールは、何かが関数プロトタイプとして解釈できる場合、そうなるということです。括弧を削除すると、問題ありません。

dataStructure ds; // <-- note
ds.timeOperation(ds.insertionSort());

あなたのコメントへの回答は、プロトタイプとして解釈できない限り、あなたは良いです. 検討:

struct S {};

struct dataStructure
{
   dataStructure() {}
   dataStructure(int) {}
   dataStructure(S) {}
   void go() {}
};

int main()
{
    dataStructure ds1 = dataStructure();
    dataStructure ds2(10);
    dataStructure ds3( S() ); 
    dataStructure ds4( (S()) ); // Extra parens clarify for the compiler


    ds1.go(); // Ok  
    ds2.go(); // Ok  
    ds3.go(); // Doh! ds3 is a function prototype
    ds4.go(); // Ok  
}

Edit 2 の更新:

この行を変更します。

als.timeOperation(als.insertionSort());

に:

als.timeOperation([&](){als.insertionSort()});

または(あまり好ましくありませんが、ラムダがない場合):

als.timeOperation( std::bind( &arrayListStruction::insertionSort, als ) );
于 2013-02-04T19:22:21.500 に答える
2

操作のタイミングを計っているので、オーバーヘッドを可能な限り最小限に抑える必要があります。

#include <functional>
#include <ctime>
#include <iostream>

void insertionSort() { /*...*/ }

template<typename F>
std::clock_t timeOfOperation( F&& operation ) {
  const std::clock_t start = std::clock();
  // time 1
  operation();
  //time 2
  return std::clock() - start;
}

int main() {
  std::cout << timeOfOperation(insertionSort) << '\n';
}

テンプレートを除いて、これは @metal のソリューションです。経由で関数を呼び出すには、適度なオーバーヘッドがありますstd::function。欠点として、これは、実装をtimeOfOperationヘッダー ファイルに配置する必要があることを意味します。

余談ですが、コンパイラが C++11 をサポートしていない場合&&は、シグネチャの を にドロップしtimeOfOperationます。これは、実際には必要ない C++ の機能です。

複数行のコードの状態を計測したい場合は、次のようにします。

void sort( int* buff, size_t count ) { /* ... */ }

int main() {
  enum { size_of_data = 10 };
  int data[size_of_data] = {1,2,3,4,5,6,-1,0};
  std::cout << timeOfOperation([&](){
    sort( &data[0], size_of_data );
  }) << '\n';
}

同じtimeOfOperationように、そこに書いたラムダはテンプレート化されたファンクターとして渡され、timeOfOperationオーバーヘッドなしで呼び出されます。

于 2013-02-04T19:30:21.340 に答える