简体   繁体   中英

CRTP how to make a derived class have a container of base class

I would like to mimic the following behavior using CRTP:

#include <vector>
#include <memory>

class GameNumber {
public:
    ~GameNumber(){}
};

class GameNumber_real : public GameNumber {
public:
    GameNumber_real (float m) {n = m;}
    ~GameNumber_real(){}
private:
    float n;
};

class GameNumber_sets : public GameNumber {
public:
    GameNumber_sets (float n, float m) {
        left.push_back (std::make_shared<GameNumber_real>
            (GameNumber_real(n)));
        right.push_back (std::make_shared<GameNumber_real>
            (GameNumber_real(m)));
    }
    ~GameNumber_sets(){}
private:
    std::vector <std::shared_ptr<GameNumber>> left;
    std::vector <std::shared_ptr<GameNumber>> right;
};

My attempt was:

template <class T>
class GameNumber {}

class GameNumber_real : public GameNumber<GameNumber_real> {
public:
    GameNumber_real (float m) {n = m;}
private:
    float n;
};

class GameNumber_sets : public GameNumber<GameNumber_sets> {
public:
    GameNumber_sets (float n, float m) {
        left.push_back (std::make_shared<GameNumber_real>
            (GameNumber_real(n)));
        right.push_back (std::make_shared<GameNumber_real>
            (GameNumber_real(m)));
    }
private:
    std::vector <std::shared_ptr<GameNumber>> left;
    std::vector <std::shared_ptr<GameNumber>> right;
};

The compiler error is:

include/game_number.hpp:44:33: error: no matching function for call to
‘std::vector<std::shared_ptr<GameNumber<GameNumber_sets>>>
::push_back(std::shared_ptr<GameNumber_real>)’  
             (GameNumber_real(n)));

From the message I understand that inside GameNumber_sets, GameNumber resolves to GameNumber_GameNumber_sets_. I would be really glad if you could tell me how achieve the behavior I expected.

You can explicitly specify template argument like GameNumber<GameNumber_real> and it will solve your problem.

Also you can pass constructor arguments directly to std::make_shared .

Improved code:

template <class T>
class GameNumber {};

class GameNumber_real : public GameNumber<GameNumber_real> {
public:
    GameNumber_real (float m) {n = m;}
private:
    float n;
};

class GameNumber_sets : public GameNumber<GameNumber_sets> {
public:
    GameNumber_sets (float n, float m) {
        left.push_back (std::make_shared<GameNumber_real>(n));
        right.push_back (std::make_shared<GameNumber_real>(m));
    }
private:
    std::vector <std::shared_ptr<GameNumber<GameNumber_real>>> left;
    std::vector <std::shared_ptr<GameNumber<GameNumber_real>>> right;
};

However I don't understand why do you need CRTP in here, there is no use of it in your example.

Edit:

As far as I know you can't use CRTP as interface. However there is std::any ( https://en.cppreference.com/w/cpp/utility/any ) which may help if c++17 is ok for you.

Code would look like:

template <class T>
class GameNumber {};

class GameNumber_real : public GameNumber<GameNumber_real> {
public:
    GameNumber_real (float m) {n = m;}
private:
    float n;
};

class GameNumber_sets : public GameNumber<GameNumber_sets> {
public:
    GameNumber_sets (float n, float m) {
        left.push_back (std::make_shared<std::any>
            (GameNumber_real(n)));
        right.push_back (std::make_shared<std::any>
            (GameNumber_real(m)));
    }
private:
    std::vector <std::shared_ptr<std::any>> left;
    std::vector <std::shared_ptr<std::any>> right;
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM