我阅读了Wikipedia article关于C中用于执行静态(读取:编译时)多态的奇怪重复出现的模板模式 . 我想概括它,以便我可以根据派生类型更改函数的返回类型 . (这似乎应该是可能的,因为基类型知道模板参数中的派生类型) . 不幸的是,以下代码现在很容易访问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> { ... };
EDIT:
MSVC 2010在这种情况下提供的错误消息是 error C2039: 'value_type' : is not a member of 'derived<T>'
g 4.1.2(通过codepad.org)说 error: no type named 'value_type' in 'class derived<int>'
5 回答
derived
在其基类列表中将其用作base
的模板参数时不完整 .常见的解决方法是使用traits类模板 . 这是你的例子,traitsified . 这显示了如何通过特征使用派生类中的类型和函数 .
您只需要将
base_traits
专门用于derived_t
的derived_t
的模板参数的任何类型,并确保每个专门化都提供base
所需的所有成员 .使用traits的一个小缺点是你必须为每个派生类声明一个 . 您可以编写一个不那么详细和重新划分的解决方法,如下所示:
在C 14中你可以删除
typedef
并使用函数auto
返回类型扣除:这是有效的,因为
base::foo
的返回类型的推断被延迟,直到derived_t
完成 .对需要较少样板文件的类型特征的替代方法是将派生类嵌套在包含typedef(或使用)的包装类中,并将包装器作为模板参数传递给基类 .
我知道这基本上是你找到并且不喜欢的解决方法,但我想记录它,并且说它基本上是这个问题的当前解决方案 .
我一直在寻找一种方法来做这件事,从来没有找到一个好的解决方案 . 事实上,这是不可能的,这就是为什么最终像
boost::iterator_facade<Self, different_type, value_type, ...>
这样的东西需要很多参数 .当然,我们希望这样的东西能起作用:
如果这是可能的,派生类的所有特征都可以隐式地传递给基类 . 我发现获得相同效果的成语是完全将特征传递给基类 .
https://godbolt.org/z/2G4w7d
缺点是必须使用合格的
typename
或using
重新启用派生类中的特征 .