继承类型定义
Inheriting typedefs?
我最近被几个代码示例弄糊涂了——有时继承基类公开的类型似乎可以工作,有时似乎不能。
我的问题是
- 为什么它不总是工作?
- 在什么情况下它会/不会工作?
- 当它不起作用时,有什么好的解决办法?
下面是一些特定的代码:
// First example: Inheriting `static const int ...`
// Basic TypeList object
template<typename... Ts>
struct TypeList {
static const int size = sizeof...(Ts);
};
// Repeat metafunction
template<typename T>
struct repeat;
template<typename... Ts>
struct repeat<TypeList<Ts...>> : TypeList<Ts..., Ts...> {};
// Checks
typedef TypeList<int, float, char> MyList;
static_assert(MyList::size == 3, "D:");
static_assert(repeat<MyList>::size == 6, "D:");
// Second example: Inheriting typedefs
// Meta function to compute a bundle of types
template <typename T>
struct FuncPtrTypes {
typedef int result_type;
typedef T input_type;
typedef result_type(*func_ptr_type)(input_type);
};
// template <typename T, typename FuncPtrTypes<T>::func_ptr_type me>
// struct FuncPtr : FuncPtrTypes<T> {
// static result_type apply(input_type i) {
// return me(i);
// }
// };
//
// Doesn't compile (?): clang 3.6:
// main.cpp:34:9: error: unknown type name 'result_type'
// static result_type apply(input_type i) {
// ^
// main.cpp:34:27: error: unknown type name 'input_type'
// static result_type apply(input_type i) {
// ^
//
// g++ 4.8.4:
// main.cpp:34:9: error: ‘result_type’ does not name a type
// static result_type apply(input_type i) {
// ^
// main.cpp:34:9: note: (perhaps ‘typename FuncPtrTypes<T>::result_type’ was intended)
// This compiles but is clumsy:
template <typename T, typename FuncPtrTypes<T>::func_ptr_type me>
struct FuncPtr {
typedef typename FuncPtrTypes<T>::input_type input_type;
typedef typename FuncPtrTypes<T>::result_type result_type;
static result_type apply(input_type i) {
return me(i);
}
};
// A non-template example:
struct foo {
typedef int bar;
};
struct baz : foo {};
typedef baz::bar bazbar;
// ^ This compiles... huh??
int main() {}
我们可以把你失败的例子简化为:
template <typename T>
struct Base { using type = T; };
template <typename T>
struct Derived : Base<T>
{
type mem; // error: 'type' does not name a type
};
问题是这里的type
是一个依赖于的名称。它取决于 T
。对于给定的T
,不能保证没有没有命名type
的Base<T>
的某些专门化。因此,类模板的基模板不是标准名称查找的一部分,因此必须对其进行限定:
Base<T>::type mem;
尽管现在我们遇到了规则的冲突,该规则表明除非显式声明,否则依赖名称不会被假定为类型,所以您需要:
typename Base<T>::type mem;
OP中提供的其他情况都不依赖于对从属名称的非限定查找。
回到具体的问题,这不能编译:
static result_type apply(input_type i) {
,因为result_type
和input_type
是依赖类型,所以必须限定并加上typename
:
static typename FuncPtrTypes<T>::result_type apply(typename FuncPtrTypes<T>::input_type i) {
或者,如果您愿意,您可以简单地使用using-declaration:
将两个名称都引入 using typename FuncPtrTypes<T>::input_type;
using typename FuncPtrTypes<T>::result_type;
static result_type apply(input_type i) {
将编译以下代码:
template <typename T, typename FuncPtrTypes<T>::func_ptr_type me>
struct FuncPtr : FuncPtrTypes<T> {
static typename FuncPtrTypes<T>::result_type apply(typename FuncPtrTypes<T>::input_type i) {
return me(i);
}
};
问题基本上是c++模板在编译过程中有两个阶段的查找。第一阶段是语法查找,而第二阶段根据实际类型执行编译。
进一步展开:
问题是result_type可能是一个全局符号或继承的,并且在查找的第一阶段假定它是全局的,因为依赖于T的类型在编译的该阶段/阶段没有被解析/求值。
参见:在需要typename的地方
另一个可能的解决方案是使用特征(例如):
template <class T>
struct FuncPtrTraits
{
typedef int result_type;
typedef T input_type;
typedef result_type(*func_ptr_type)(input_type);
};
template <typename T, typename TraitsT = FuncPtrTraits<T> >
struct FuncPtr
static typename TraitsT::result_type apply(typename TraitsT::input_type i) {
return me(i);
}
};
如果设计正确,trait可以帮助你从外部修改代码,当你从基本trait类型继承时,也可以部分地修改代码。
相关文章:
- 使用QJsEngine在Qt中注册自定义类型
- 在UE4中使用未定义类型'UTextBlock'
- 修改"std::set"中用户定义类型的值
- 当我使用自定义类型创建动态数组时,即使使用字符串,它似乎也不起作用
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 如何使自定义类型在unordered_map中用作键
- 在 C++20 中是否不再允许在 std 中对程序定义类型的函数模板进行专用化?
- Qt5 远程对象 + 自定义类型,但不在 POD 中
- 为什么转换函数声明不需要至少一个定义类型说明符
- 标准::原子中的自定义类型
- 如何使用自定义类型声明Arduino数组?
- 如何在 Cython 中定义返回 cpp 定义类型的函数?
- 使用自定义访问者时具有自定义类型的提升变体失败(源自 boost::static_visitor)
- 您可以将binary_search应用于具有自定义类型的矢量吗?
- 在自定义类型图中重用 SWIG 映射
- 扩展自定义类型的spdlog
- vim使用户定义类型的COLOR与C++中的基本类型相同
- 重载自定义类型的 std::to_string 和 std::to_chars?
- 具有未声明/未定义类型的 typedef 结构
- 函数重载:内置类型与用户定义类型