I want to make GroupBase as a interface...
#include "string"
#include "unordered_map"
template<class Vty>
class BaseV {
public:
BaseV() {
//logic
}
virtual auto run() -> bool { return false; }
protected:
//members
};
class GroupBase {
public:
GroupBase() {
//logic
}
template<class Vty>
auto run(const std::string &name, const Vty &value) -> void {
createValue<Vty>(name);
((BaseV *)_values.at(name))->run();
}
template<class Vty>
auto createValue(const std::string &name) -> void {
static_assert(false, "You must override createValue method to instead GroupBase::createValue!");
}
protected:
std::unordered_map<std::string, void*> _values{};
};
template<class Vty>
class ThirdPartyClass{};
template<class Vty>
class DerivedV : public BaseV<Vty> {
public:
DerivedV() : BaseV<Vty>() {
_data = new ThirdPartyClass<Vty>();
}
auto run() -> bool override {
//call function in _data;
}
protected:
ThirdPartyClass<Vty>* _data;
};
class GroupDerived : public GroupBase {
public:
GroupDerived () : GroupBase() {
//logic
}
template<class Vty>
auto createValue(const std::string &name) -> void {
_values.emplace(name, new DerivedV<Vty>());
}
};
int main(int argc, char** argv) {
auto group = GroupDerived();
group.run("a", 1);
}
Of course this code cannot work.It will print the message in static_assert
an compile will failed.
If remove this line:
static_assert(false, "You must override createValue method to instead GroupBase::createValue!");
It worked, but an warning will occur.
So how to make it more reasonable? (I have to add a new ThirdPartyClass 1, 2, 3...at any time...)
You may want to look into the CRTP pattern for this, if I understand your intent correctly. Also, your outline has no way to properly free dynamic memory, you better derive BaseV
from a common interface with a virtual destructor, say IBaseValue
.
// Type MUST implement template method createValue(const std::string&)
template<typename Type>
struct Creator {
template<typename ValueType>
void run(const std::string& name, const ValueType& value){
//to catch a case of stupid BaseV specialization
static_assert(std::is_base_of_v<IBaseValue, BaseV<ValueType>>);
//confused: we don't use 'value' argument at all?
static_cast<Type*>(this)->template createValue<ValueType>(name);
}
protected:
//s.t. the destructor properly frees memory
std::unordered_map<std::string, std::unique_ptr<IBaseValue>> _values{};
//To prevent accidental Creator object creation
Creator(void) = default;
};
struct GroupDerived : public Creator<GroupDerived> {
template<class Vty>
auto createValue(const std::string &name) -> void {
_values.emplace(name, new DerivedV<Vty>());
}
};
int main(void){
auto group = GroupDerived();
group.run("a", 1); //Creator<GroupDerived>::run<int>();
}