C++静态多态性 (CRTP) 和使用派生类的 typedef
我阅读了 维基百科文章,内容涉及 C++ 中用于执行静态(阅读:编译时)多态性的奇怪重复模板模式。我想概括它,以便我可以根据派生类型更改函数的返回类型。 (这似乎应该是可能的,因为基类型知道模板参数的派生类型)。不幸的是,以下代码无法使用 MSVC 2010 进行编译(我现在无法轻松访问 gcc,所以我还没有尝试过)。有人知道为什么吗?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
顺便说一句,我有一个使用额外模板参数的解决方法,但我不喜欢它——当在继承链上传递许多类型时,它会变得非常冗长。
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
编辑:
MSVC 2010 在这种情况下给出的错误消息是 error C2039: 'value_type' : is not a member of 'driven
g++ 4.1.2 (通过codepad.org)说错误:“class”中没有名为“value_type”的类型派生
I read the Wikipedia article about the curiously recurring template pattern in C++ for doing static (read: compile-time) polymorphism. I wanted to generalize it so that I could change the return types of the functions based on the derived type. (This seems like it should be possible since the base type knows the derived type from the template parameter). Unfortunately, the following code won't compile using MSVC 2010 (I don't have easy access to gcc right now so I haven't tried it yet). Anyone know why?
template <typename derived_t>
class base {
public:
typedef typename derived_t::value_type value_type;
value_type foo() {
return static_cast<derived_t*>(this)->foo();
}
};
template <typename T>
class derived : public base<derived<T> > {
public:
typedef T value_type;
value_type foo() {
return T(); //return some T object (assumes T is default constructable)
}
};
int main() {
derived<int> a;
}
BTW, I have a work-around using extra template parameters, but I don't like it---it will get very verbose when passing many types up the inheritance chain.
template <typename derived_t, typename value_type>
class base { ... };
template <typename T>
class derived : public base<derived<T>,T> { ... };
EDIT:
The error message that MSVC 2010 gives in this situation is error C2039: 'value_type' : is not a member of 'derived<T>'
g++ 4.1.2 (via codepad.org) says error: no type named 'value_type' in 'class derived<int>'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当您将它用作其基类列表中的
base
的模板参数时,衍生
是不完整的。常见的解决方法是使用特征类模板。这是你的例子,有特征。这展示了如何通过特征使用派生类中的类型和函数。
您只需将
base_traits
专门化为用于base
的模板参数衍生_t
的任何类型,并确保每个专门化都提供所有base
需要的成员。derived
is incomplete when you use it as a template argument tobase
in its base classes list.A common workaround is to use a traits class template. Here's your example, traitsified. This shows how you can use both types and functions from the derived class through the traits.
You just need to specialize
base_traits
for any types that you use for the template argumentderived_t
ofbase
and make sure that each specialization provides all of the members thatbase
requires.使用特征的一个小缺点是您必须为每个派生类声明一个特征。您可以编写一个不太冗长且冗余的解决方法,如下所示:
One small drawback of using traits is that you have to declare one for each derived class. You can write a less verbose and redondant workaround like this :
在 C++14 中,您可以删除
typedef
并使用函数auto
返回类型推导:这有效,因为推导了
base::foo< 的返回类型/code> 被延迟,直到
衍生_t
完成。In C++14 you could remove the
typedef
and use functionauto
return type deduction:This works because the deduction of the return type of
base::foo
is delayed untilderived_t
is complete.需要较少样板文件的类型特征的替代方法是将派生类嵌套在保存 typedef(或 using)的包装类中,并将包装器作为模板参数传递给基类。
An alternative to type traits that requires less boilerplate is to nest your derived class inside a wrapper class that holds your typedefs (or using's) and pass the wrapper as a template argument to your base class.
我知道这基本上是您发现但不喜欢的解决方法,但我想记录它,并说它基本上是该问题的当前解决方案。
我一直在寻找一种方法来做到这一点,但从未找到好的解决方案。
事实上,这是不可能的,这就是为什么像
boost::iterator_facade
这样的东西最终需要许多参数的原因。当然,我们希望像这样的东西能够工作:
如果可能的话,派生类的所有特征都可以隐式传递给基类。我发现获得相同效果的惯用法是将特征完全传递给基类。
https://godbolt.org/z/2G4w7d
缺点是派生类中的特征具有可以使用限定的
typename
进行访问,或者通过using
重新启用。I know that this is basically the workaround you found and don't like, but I wanted to document it and also to say that it is basically the current solution to this problem.
I have been looking for a way to do this for a while and never found a good solution.
The fact that it is not possible is the reason why ultimately, things like
boost::iterator_facade<Self, different_type, value_type, ...>
need many parameters.Of course we would like something something like this to work:
If this was possible, all the traits of the derived class could be passed implicitly ot the base class. The idiom I found to get the same effect is to pass the traits to the base class entirely.
https://godbolt.org/z/2G4w7d
The drawback is that the trait in the derived class has to be accessed with a qualified
typename
or reenabled byusing
.