我使用了“奇怪地重复出现的模板模式”来继承一个静态成员变量和一个实例getter。 听起来有些做作,但是这个项目将会有很多很多的子类,它们需要尽可能轻松地声明,而不需要重复代码。
我想出了以下方法,效果很好:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
struct Base {
virtual void printStrings() = 0;
};
template <typename T>
struct static_strings: Base {
static std::vector<std::string> strings;
static void addString(const std::string& s) {
strings.push_back(s);
}
virtual void printStrings() {
for (auto s: T::strings) {
std::cout << s << std::endl;
}
}
};
template <typename T> std::vector<std::string> static_strings<T>::strings;
struct Sub1: static_strings<Sub1> {};
struct Sub2: static_strings<Sub2> {};
int main() {
Sub1::addString("test 1");
std::shared_ptr<Base> s1 = std::make_shared<Sub1>();
Sub2::addString("test 2");
std::shared_ptr<Base> s2 = std::make_shared<Sub2>();
std::cout << "s1: ";
s1->printStrings();
std::cout << "s2: ";
s2->printStrings();
return 0;
}
但是,我想进一步简化新子类的声明,因为现在我必须复制声明并在粘贴行中更改类名两次(structsub3:static_strings
)。 我可以使用宏,但我想知道是否有一个非宏(模板?) 怎么做?
您可以轻松地更改base
tp,使用一组要派生的模板参数:
template <typename T, template<typename> typename... OtherBases>
struct Base : OtherBases<T>... {
[...]
};
struct Sub1: Base<Sub1, static_strings> {};
struct Sub2: Base<Sub2, static_strings> {};
这不是一个很大的胜利,但如果你有更多的crtp基础类,这可能会有所帮助。 但是,我无法想像没有宏就能保存剩余重复的方法。
这里是实时代码。
对于shared_pointer,您需要从一个额外的非模板基类派生。
struct AbstractBase {
virtual ~AbstractBase() = default;
virtual void printStrings() = 0;
};
template <typename T, template<typename> typename... OtherBases>
struct Base : AbstractBase, OtherBases<T>... {... };
然后从该指针创建共享指针:
std::shared_ptr<AbstractBase> s1 = std::make_shared<Sub1>();
std::shared_ptr<AbstractBase> s2 = std::make_shared<Sub2>();
请参阅此处获得更新示例。
您可以使用帮助程序类型:
struct helper : foo<helper>, bar<helper> {};
仅仅这样做是不行的,因为从它继承的所有类型将共享相同的基类。 为了避免重复类型名,可以引入一个虚拟模板参数:
template <typename T>
struct foo {};
template <typename T>
struct bar{};
template <int x>
struct helper : foo<helper<x>>, bar<helper<x>> {};
using Sub1 = helper<1>;
using Sub2 = helper<2>;
int main () {
}
这就是不需要宏就能做到的。 对于宏,您可以使用__counter__
(gcc有它,不确定其他的)来获取不同的int
s:
using SubA = helper<__COUNTER__>;
using SubB = helper<__COUNTER__>;