不太确定如何在此处表述标题。
问题是我有一个类模板:
template<various parameters> struct Base { ... };
然后我有一组从中派生的开放类:
struct A: public Base<some arguments> { ... };
struct B: public Base<other arguments> { ... };
struct C: public Base<different arguments> { ... };
...
重要的是,派生类除了固定模板参数之外没有向 Base 添加任何内容——不是成员函数,尤其是成员变量。所以他们的二进制表示应该都是一样的。我使用继承而不是 typedef 的唯一原因是我希望能够前向声明 A、B、C 等(或者更准确地说,A、B、C 等由客户使用提供的宏,为了他们的方便,我希望他们能够前向声明。)拥有 A、B、C 等的原因是为了避免必须写出始终手动模板参数。
问题是 Base 有一些函数将回调作为参数,并且回调应该将对类本身的引用作为参数。
所以我希望有像这样的回调函数:
void foo (A&, ...);
void bar (B&, ...);
等等。在 Base 中实现回调函数时,我想将 *this 作为参数传递给回调。很明智地,C++ 不允许我这样做,因为在预期派生类的地方传递基类通常是不安全的。但在这种特定情况下,这应该不是问题,因为派生类不会向基类添加任何内容,而只是用来代替 typedef。
看来我有三个标准:
- 我希望“typedef”是前向声明的。
- 我需要能够将基类传递给回调。
- 我希望能够使用“typedef”而不是基类来声明回调。
两者互不相容。 (第三个标准再次是为了客户的方便,因为每次都将模板参数手动写到基类中会非常冗长,而不想这样做是拥有'typedefs的全部原因'.)
我看到三种解决方案:
放弃第一个或第三个标准。
某种丑陋而复杂的方案,我检查回调函数需要什么样的参数,并验证它是基类的伪类型定义(通过检查 sizeof 是否相同以及通过 SFINAE 确定它是从基础派生,或检查由生成伪 typedef 的宏插入的某种标记,或类似的东西),然后执行强制转换。
还有更好的吗?
(允许使用 C++11。)
最佳答案
雇用CRTP idiom并在模板参数中也传递派生类。对于回调,只需将 *this
转换为派生类型即可。
template<class Derived, other params...>
struct Base{
template<class F>
void do_callback_stuff(F func){
func(static_cast<Derived&>(*this), ....);
}
};
struct A : public Base<A, other args...>{};
关于c++ - 使用继承而不是 typedef 来实现前向可声明性和回调带来的复杂性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8175155/