Reputation: 6425
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
Reputation: 69882
There are two rules:
Use a static const bool, initialised by a static registration function.
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
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