javaLover
javaLover

Reputation: 6425

Call all possible template function in advance corresponding to ANOTHER template function

For every T in f2<T>() that might be called, how to force all f1<T> to be called in a certain function f1_advanced() in advance?

class Manager(){
    public: void f1_advanced (){ /* add code here */ }
    private: template<class T> void f1 (){  }
    public:  template<class T> void f2 (){  }
}


class Usage{
    void testCase(){
        Manager manager;
        manager.f1_advanced();
        //^^ Must call f1<A> and f1<B> automatically.
        //   Whether it calls f1<C> or not, both cases are ok for me.
        manager.f2<A>();
        manager.f2<B>();
        if(false) manager.f2<C>();
    }
}

Note: A, B, ... are derived from a certain class T0.

I have searched, but don't find any solution, don't know what this feature is called, or even whether this is possible.

I just believe it can be done with some advanced template magic.

Upvotes: 0

Views: 73

Answers (2)

Richard Hodges
Richard Hodges

Reputation: 69882

There are two rules:

  1. Use a static const bool, initialised by a static registration function.

  2. All games must be written in character

Here is my goblin game

#include <unordered_map>
#include <vector>
#include <string>
#include <typeindex>
#include <iostream>

//
// base game object, suplpying polymorphic interface

struct GameObject
{
    virtual void identify_thyself() const = 0;

    GameObject() noexcept {}
    GameObject(GameObject&&) noexcept = default;
    GameObject(GameObject const&) noexcept = default;
    GameObject& operator=(GameObject&&) noexcept = default;
    GameObject& operator=(GameObject const&) noexcept = default;
    virtual ~GameObject() = default;
};

// every game should be written in character, or you're not doing it right

template<class T>
struct ye {};

// an object manager which allows static registration of creation functions

struct Manager
{
    using game_object_ptr = std::unique_ptr<GameObject>;
    using create_object_function = std::function<game_object_ptr()>;
    struct static_data
    {
        std::unordered_map<
        std::type_index,
        create_object_function
        > creation_functions;
    };

    static static_data& get_static_data()
    {
        static static_data sd {};
        return sd;
    }

    template<class T>
    static void register_object(create_object_function creator) {
        auto& statics = get_static_data();
        // do whatever registration is required here
        statics.creation_functions.emplace(typeid(T), std::move(creator));
    }

    template<class T>
    static game_object_ptr create_monster(ye<T>)
    {
        // this will throw an exeption if the object wasn't registered
        return get_static_data().creation_functions.at(typeid(T))();
    }

};

// introducing: Ye Goblins!

struct Goblin : GameObject
{
    Goblin(std::string name)
    : _name(std::move(name))
    {}

    void identify_thyself() const override { std::cout << _name << " the goblin, waiting to a-slit your throat!\n"; }
    static const bool registered;
    std::string _name;
};
const bool Goblin::registered = [] {
    Manager::register_object<Goblin>([]()->Manager::game_object_ptr{
        static const std::vector<std::string> namez {
            "Grunt",
            "Basher",
            "Pulveriser",
            "Squisher"
        };
        static int iname = 0;
        auto next_name = [&] {
            auto s = namez[iname];
            ++iname;
            if (iname >= namez.size()) iname = 0;
            return s;
        };

        return std::make_unique<Goblin>(next_name());
    });
    return true;
}();

struct Hero : GameObject
{
    void identify_thyself() const override { std::cout << "Harry the hero, waiting to degoblinise this blessed land!\n"; }
    static const bool registered;
};

const bool Hero::registered = [] {
    Manager::register_object<Hero>([]()->Manager::game_object_ptr{
        return std::make_unique<Hero>();
    });
    return true;
}();

struct appear_verb {};
static constexpr appear_verb appear {};
static constexpr appear_verb appears {};

struct goblinator
{
    auto operator,(appear_verb) const
    {
        std::vector<Manager::game_object_ptr> ye_hoard;
        std::generate_n(std::back_inserter(ye_hoard), 4,
                        [] { return Manager::create_monster(ye<Goblin>()); } );
        return ye_hoard;
    }
};

static constexpr goblinator a_number_of_merry_goblins {};

struct heroinator
{
    auto operator, (appear_verb) const
    {
        return Manager::create_monster(ye<Hero>());
    }
};
static constexpr heroinator our_hero {};

struct identify_thyselfer
{
    void operator, (const Manager::game_object_ptr& ptr) const {
        ptr->identify_thyself();
    }
};
static constexpr identify_thyselfer identify_thyself{};

struct identify_thyselvser
{
    void operator, (std::vector<Manager::game_object_ptr> const& them) const
    {
        for (auto& yeself : them)
        {
            yeself->identify_thyself();
        }
    }
};
static constexpr identify_thyselvser identify_thyselves{};

struct methinkser
{
    template<class T>
    decltype(auto) operator, (T const& musings) const
    {
        return std::cout << musings << '\n';
    }
};
static constexpr methinkser methinks {};


int main()
{
//    Manager ye_manager; // not necessary since manager registration is static


    methinks, "Introducing, the Goblins:";
    auto ye_goblins = (a_number_of_merry_goblins, appear);
    identify_thyselves, ye_goblins ;

    methinks, "";
    methinks, "Introducing, the Hero:";
    auto ye_hero = (our_hero, appears);
    identify_thyself, ye_hero;
}

Example output while playing this engaging game:

Introducing, the Goblins:
Grunt the goblin, waiting to a-slit your throat!
Basher the goblin, waiting to a-slit your throat!
Pulveriser the goblin, waiting to a-slit your throat!
Squisher the goblin, waiting to a-slit your throat!

Introducing, the Hero:
Harry the hero, waiting to degoblinise this blessed land!

Upvotes: 2

Chris
Chris

Reputation: 615

The compiler cannot know all the possible type deductions for your Manager class. The best thing you can do is write a wrapper function that takes in a list of them that have been explicitly instantiated and calls their functions that you want to test.

Upvotes: 0

Related Questions