继承类型定义?
Inheriting typedefs?
我最近对一些代码示例感到困惑 -- 有时似乎继承由基 class 公开的 typedef 有效,有时似乎无效。
我的问题是
- 为什么它总是不起作用?
- 它在什么情况下会/不会工作?
- 当它不起作用时有什么好的解决方法?
下面是一些具体的代码:
// 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, 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 不是 parsed/evaluated 在 stage/phase 的编译。
参见:where typenames are required
您的问题的另一种可能的解决方案是使用特征(例如):
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);
}
};
如果设计得当,特征可以帮助您从外部修改代码,并且当您从基本特征类型继承时也可以部分修改代码。
我们可以将您的失败示例简化为:
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
这里是一个 dependent 名字。它 取决于 T
。不能保证对于给定的 T
没有 Base<T>
的一些特化,它没有命名 type
。因此,class 模板的基本模板不是标准名称查找的一部分,因此您必须对其进行限定:
Base<T>::type mem;
虽然现在我们 运行 违反了规则,该规则表明除非明确说明,否则不假定从属名称是类型,因此您需要:
typename Base<T>::type mem;
None OP 中出现的其他案例依赖于对从属名称的非限定查找。
到return到具体问题,这个编译不通过:
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) {
我最近对一些代码示例感到困惑 -- 有时似乎继承由基 class 公开的 typedef 有效,有时似乎无效。
我的问题是
- 为什么它总是不起作用?
- 它在什么情况下会/不会工作?
- 当它不起作用时有什么好的解决方法?
下面是一些具体的代码:
// 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, 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 不是 parsed/evaluated 在 stage/phase 的编译。
参见:where typenames are required
您的问题的另一种可能的解决方案是使用特征(例如):
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);
}
};
如果设计得当,特征可以帮助您从外部修改代码,并且当您从基本特征类型继承时也可以部分修改代码。
我们可以将您的失败示例简化为:
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
这里是一个 dependent 名字。它 取决于 T
。不能保证对于给定的 T
没有 Base<T>
的一些特化,它没有命名 type
。因此,class 模板的基本模板不是标准名称查找的一部分,因此您必须对其进行限定:
Base<T>::type mem;
虽然现在我们 运行 违反了规则,该规则表明除非明确说明,否则不假定从属名称是类型,因此您需要:
typename Base<T>::type mem;
None OP 中出现的其他案例依赖于对从属名称的非限定查找。
到return到具体问题,这个编译不通过:
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) {