您将如何在模板中定义未定义的函数?

发布于 2024-12-10 20:03:26 字数 2451 浏览 3 评论 0原文

我正在编写一个 C++ 项目,并且在类模板中有一个通用的评估方法。

我唯一的问题是如何定义 generateAllMovesisPosFinal 以便在使用该类模板的类中定义它?

我读到使用纯虚函数是不行的。我也不想让它静态。

我预见自己会将其重写为抽象类,但最终会遇到需要泛型类型的问题。

#ifndef ENGINE_H
#define ENGINE_H

#include <map>

using namespace std;

template< class M, class P >

class Engine {

public:

  Engine() { };  

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {

      map< M , P > allMoves = generateAllMoves( position );

      typename map< M , P > :: iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }
};

#endif

编辑:为了让大家更清楚!

我有两个不同的游戏,它们定义了自己的generateAllMoves 和isPosFinal 方法。它们使用不同的算法并返回不同的类型......例如,我很快就会实现一个国际象棋游戏,但现在我正在实现 nim。两者对移动和该位置最终的解释不同。

第二次编辑:

最终代码编译!

#ifndef ENGINE_H
#define ENGINE_H

#include <map>

using namespace std;

template< typename Derived, class M, class P >

class Engine {

public:

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( static_cast<Derived*>(this)->posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {

      map< M , P > allMoves = static_cast<Derived*>(this)->generateAllMoves( position );

      typename map< M , P > :: iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }

  bool posIsFinal( P position ) {
    cerr << "Generic posIsFinal\n";
    exit(1);
  }

  map< M , P > generateAllMoves( P position ) {
    cerr << "Generic generateAllMoves\n";
    exit(1);
  }

private:


};

#endif

I'm writing a C++ project and have a generic evaluate method in a class template.

My only question is how would I define the generateAllMoves and isPosFinal so that it is defined inside the classes that use this class template?

I've read that using pure virtual functions is a no no. I also do not want to make it static.

I foresee myself rewriting this as an abstract class, but then I would end up with a problem that requires generic types.

#ifndef ENGINE_H
#define ENGINE_H

#include <map>

using namespace std;

template< class M, class P >

class Engine {

public:

  Engine() { };  

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {

      map< M , P > allMoves = generateAllMoves( position );

      typename map< M , P > :: iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }
};

#endif

Edit: To be more clear for everyone!

I have two different games right that defines its own generateAllMoves and isPosFinal methods. They use different algorithms and return different types.... For example, I will be soon implementing a chess game, but right now I'm implementing nim. Both interpret move and is this position final, differently.

2nd Edit:

Final code compiles!

#ifndef ENGINE_H
#define ENGINE_H

#include <map>

using namespace std;

template< typename Derived, class M, class P >

class Engine {

public:

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( static_cast<Derived*>(this)->posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {

      map< M , P > allMoves = static_cast<Derived*>(this)->generateAllMoves( position );

      typename map< M , P > :: iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }

  bool posIsFinal( P position ) {
    cerr << "Generic posIsFinal\n";
    exit(1);
  }

  map< M , P > generateAllMoves( P position ) {
    cerr << "Generic generateAllMoves\n";
    exit(1);
  }

private:


};

#endif

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风筝在阴天搁浅。 2024-12-17 20:03:26

做到这一点的一个好方法是使用“奇怪的递归模板参数”习惯用法。

请参阅此处了解更多信息

A good way to do just this is to use the "Curiously Recursive Template Parameter" idiom.

See here for more information.

拥抱我好吗 2024-12-17 20:03:26

您可以为引擎创建一个具有所有必要参数化的特征类:


template< class EngineTraits >
class Engine {

  typedef typename EngineTraits::P_type P;
  typedef typename EngineTraits::M_type M;

public:

  Engine() { };  

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( EngineTraits::posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {
      typedef typename EngineTraits::moves_mapping_type MovesMapping;
      MovesMapping allMoves = EngineTraits::generateAllMoves( position );

      typename MovesMapping::iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }
};

现在您可以通过定义适当的特征类来自定义您的引擎:


struct my_engine_traits
{
  typedef some-type P_type;
  typedef some-type M_type;
  typedef std::map<M_type, P_type> moves_mapping_type;

  static bool posIsFinal(P_type const &position)
  {
    // ...
  }

  static moves_mapping_type generateAllMoves(P_type const &position)
  {
    // ...
  }
};

或者您也可以使您的引擎客户端类成为引擎特征:


class my_engine_client
{
  typedef some-type P_type;
  typedef some-type M_type;
  typedef std::map<M_type, P_type> moves_mapping_type;

  static bool posIsFinal(P_type const &position)
  {
    // ...
  }

  static moves_mapping_type generateAllMoves(P_type const &position)
  {
    // ...
  }

  typedef Engine<my_engine_client> Engine;
  Engine m_engine;  
};

当然您可以改变直接传递的内容作为引擎模板参数以及要移动到单个 traits 类的内容,例如:


template< class M, class P, class PositionProcessor >
class Engine {
// ...
};

You could make a traits class with all necessary parameterization for the Engine:


template< class EngineTraits >
class Engine {

  typedef typename EngineTraits::P_type P;
  typedef typename EngineTraits::M_type M;

public:

  Engine() { };  

  struct Move {
    P move;
    P pos;
    int score;
  };

  Move evaluate( P position ) {

    Move best;      

    if ( EngineTraits::posIsFinal( position ) ) {
      Move newMove;
      newMove.pos = position;
      newMove.score = 1;
      return newMove;
    }

    else {
      typedef typename EngineTraits::moves_mapping_type MovesMapping;
      MovesMapping allMoves = EngineTraits::generateAllMoves( position );

      typename MovesMapping::iterator it;

      for (it = allMoves.begin(); it != allMoves.end(); it++ ) {
        Move next = evaluate(it->second);

        if (next.score > best.score ) {
          best.pos = next.pos;
          best.move = next.move;
          best.score = next.score;
        }
      }
      return best;
    }
  }
};

Now you can customize your engine by defining appropriate traits class:


struct my_engine_traits
{
  typedef some-type P_type;
  typedef some-type M_type;
  typedef std::map<M_type, P_type> moves_mapping_type;

  static bool posIsFinal(P_type const &position)
  {
    // ...
  }

  static moves_mapping_type generateAllMoves(P_type const &position)
  {
    // ...
  }
};

Or you can make your engine client class to be engine traits as well:


class my_engine_client
{
  typedef some-type P_type;
  typedef some-type M_type;
  typedef std::map<M_type, P_type> moves_mapping_type;

  static bool posIsFinal(P_type const &position)
  {
    // ...
  }

  static moves_mapping_type generateAllMoves(P_type const &position)
  {
    // ...
  }

  typedef Engine<my_engine_client> Engine;
  Engine m_engine;  
};

And surely you can vary what is passed directly as Engine template parameters and what to move to a single traits class, e.g.:


template< class M, class P, class PositionProcessor >
class Engine {
// ...
};

樱花坊 2024-12-17 20:03:26

不是特别是朋友的朋友函数,但是像这样的函数怎么样:

template< class M, class P >
class Engine {
public:
  friend void generateAllMoves(P position);
  void evaluate( P position )
  {
    ...
    generateAllMoves(position);
    ...
  }
};

// here your specific function

void generateAllMoves(int position )
{ 
  ;
}

int main(int argc, char* argv[])
{
// then instantiate it
  Engine<int,int> X;

  ..

Not particularly a friend of friend functions but how about something like this:

template< class M, class P >
class Engine {
public:
  friend void generateAllMoves(P position);
  void evaluate( P position )
  {
    ...
    generateAllMoves(position);
    ...
  }
};

// here your specific function

void generateAllMoves(int position )
{ 
  ;
}

int main(int argc, char* argv[])
{
// then instantiate it
  Engine<int,int> X;

  ..
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文