I've been confused recently by a few code examples -- sometimes it seems that inheriting typedefs exposed by a base class works, and sometimes it seems that it doesn't.
My questions are
- Why doesn't it always work?
- What are the situations that it will / won't work?
- What are the good workarounds when it doesn't work?
Here's some specific code:
// First example: Inheriting `static const int ...`
// Basic TypeList object
template
struct TypeList {
static const int size = sizeof...(Ts);
};
// Repeat metafunction
template
struct repeat;
template
struct repeat> : TypeList {};
// Checks
typedef TypeList MyList;
static_assert(MyList::size == 3, "D:");
static_assert(repeat::size == 6, "D:");
// Second example: Inheriting typedefs
// Meta function to compute a bundle of types
template
struct FuncPtrTypes {
typedef int result_type;
typedef T input_type;
typedef result_type(*func_ptr_type)(input_type);
};
// template ::func_ptr_type me>
// struct FuncPtr : FuncPtrTypes {
// 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::result_type’ was intended)
// This compiles but is clumsy:
template ::func_ptr_type me>
struct FuncPtr {
typedef typename FuncPtrTypes::input_type input_type;
typedef typename FuncPtrTypes::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() {}
Answer
We can simplify your failing example down to:
template
struct Base { using type = T; };
template
struct Derived : Base
{
type mem; // error: 'type' does not name a type
};
The issue is that type
here is a dependent name. It depends on T
. There is no guarantee that for a given T
there isn't some specialization of Base
which does not name type
. As such, base templates of class templates are not part of the standard name lookup, so you have to qualify it:
Base::type mem;
Although now we run afoul of the rule which indicates that dependent names are not assumed to be types unless explicitly states as such, so you need:
typename Base::type mem;
None of the other cases presented in the OP rely upon unqualified lookup of a dependent name.
To return to the specific problem, this doesn't compile:
static result_type apply(input_type i) {
because result_type
and input_type
are dependent types and so must be qualified and prefixed with typename
:
static typename FuncPtrTypes::result_type apply(typename FuncPtrTypes::input_type i) {
Or, if you prefer, you can simply bring both names in with a using-declaration:
using typename FuncPtrTypes::input_type;
using typename FuncPtrTypes::result_type;
static result_type apply(input_type i) {
No comments:
Post a Comment