When compiling :
#include <vector>
template<class T> class foo {
void bar() {
std::vector<T> x;
std::vector<T>::iterator i = x.begin();
}
};
int main() {
return 0;
}
I get :
# g++ ~test.cpp
test.cpp: In member function `void foo<T>::bar()':
test.cpp:7: error: expected `;' before "i"
Shouldn't this work?
g++ version 3.4.3 on RHEL.
You can, but you need to tell it that iterator there is a type (it doesn't know, because in general it can depend on T - as vector is a template type, and could in theory have specializations for some T where iterator is a function or something else). So, you have to use typename to indicate that it is always a type:
typename std::vector<T>::iterator i = x.begin();
This should do:
template<class T> class foo {
void bar() {
std::vector<T> x;
typename std::vector<T>::iterator i = x.begin();
}
};
I'll quote the IBM C++ compiler manual:
The typename keyword (C++ only) Use
the keyword typename if you have a
qualified name that refers to a type
and depends on a template parameter.
Only use the keyword typename in
template declarations and definitions.
The following example illustrates the
use of the keyword typename:
template<class T> class A
{
T::x(y);
typedef char C;
A::C d;
}
The statement T::x(y) is ambiguous. It
could be a call to function x() with a
nonlocal argument y, or it could be a
declaration of variable y with type
T::x. C++ will interpret this
statement as a function call. In order
for the compiler to interpret this
statement as a declaration, you would
add the keyword typename to the
beginning of it. The statement A::C d;
is ill-formed. The class A also refers
to A and thus depends on a template
parameter. You must add the keyword
typename to the beginning of this
declaration:
typename A::C d; You can also use
the keyword typename in place of the
keyword class in template parameter
declarations.
In case it isn't clear what the others mean by the compiler not knowing that it's a type: at the point where the compiler parses template foo, it doesn't know that you won't later do:
namespace std {
template<>
class vector<int> {
int iterator(void);
};
}
And then instantiate foo<int>. Then vector<T>::iterator would be a function, not a type, and the relevant line in foo should fail to parse. To work without help, compilers would have to hold off parsing foo until it's instantiated, and they've found the right class to determine whether 'iterator' is a type expression or a value expression. I suspect this could lead to circular dependencies, but would certainly be especially painful to implement. So the standard says that an expression in a template which is dependent on a parameter is assumed not to be a type unless stated to be. There are two (I think) ways to state it to be a type, which are (1) use it as a base class, and (2) qualify it with typename.
OK, so in this example you're actually not allowed to specialize std::vector. And vector actually has more template parameters than just the one I've used. So in your example, the compiler could in theory assume more than it does. But the standard doesn't make special provision for the language to rely on knowledge of what templates are in namespace std, because (1) the intention is that implementations can implement namespace std in normal headers treated the same as any other headers by the compiler, and (2) C++ is supposed to be designed as language+libraries, not as "language with special-case syntax for libraries". In fact, (1) and (2) are sort of the same requirement.
Related
This bit of code compiled in C++20 (using gcc 10.1) without using the typename keyword before the dependent type std::vector<T>::iterator. Why does it compile?
#include <vector>
template<typename T>
std::vector<T>::iterator // Why does this not require "typename" before it?
f() { return {}; }
int main() {
auto fptr = &f<int>;
}
code playground
One of the new features in C++20 is Down with typename.
In C++17, you had to provide the typename keyword in nearly all† dependent contexts to disambiguate a type from a value. But in C++20, this rule is relaxed a lot. In all contexts where you need to have a type, the typename keyword is no longer mandatory.
One such context is the return type of a function in class scope, as in your example. Others include the type in a member declaration, the type on the right-hand side of a using declaration, the parameter declaration of a lambda, the type you're passing to static_cast, etc. See the paper for the full list.
† Nearly all because base-specifiers and mem-initializer-ids were always excluded, as in:
template <typename T> struct X : T::type { }; // always ok
This is okay because, well, that needs to be a type. The paper simply extends this logic (well, it has to be a type, so let's just assume it's a type) to a lot more places that have to be types.
From the reference, from c++20, in contexts where the dependent name is unambiguously a typename, the typename keyword is no longer needed. In particular:
A qualified name that is used as a declaration specifier in the (top-level) decl-specifier-seq of:
a simple declaration or function definition at namespace scope
It would be nice if this code were invalid. But it's conceptually sound, and GCC accepts it although Comeau doesn't:
template< typename > struct t;
template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!
(Edit: the above compiles but r seems no to be declared into any scope, so it is essentially ignored.)
Explicit specializations populate a kind of nether region between templates and classes. The type declared by an explicit specialization is complete once it is defined. From the compiler's standpoint, it is not a template. If it were a parameterized template, declaring an object would be impossible. Consider §14/3:
In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the dec- laration shall contain at most one declarator. When such a declaration is used to declare a class template, no declarator is permitted.
What does "is used to declare a class template" mean? Clearly a primary template declares a class template. And a partial specialization does too, according to §14.5.5/1 (FDIS numbers):
A template declaration in which the class template name is a simple-template-id is a partial specialization of the class template named in the simple-template-id.
When it comes to explicit specializations, though, the Standard speaks in terms of a declaration preceded by the token sequence template<>. It looks like a template and it names a template-name, but it doesn't seem to declare a template.
The really bizarre thing is that §14/3 restricts the number of declarators to "at most one." A function template declaration, explicit specialization or instantiation must have exactly one declarator. Any declaration involving a class template must have exactly zero… except explicit specialization, which seems to fall through the cracks. Faithfully, GCC refuses to allow
template<> struct t< int > {} r, s; // Offer valid one per specialization.
I tend to agree with GCC's interpretation, nonsense as it may be. Unfortunately, it may be inhibiting its ability to detect missing semicolons. Please, let the number of allowed declarators be exactly zero!
Several points: first, explicit specializations are not in a nether
region between templates and classes; an explicit specialization is a
class, period. The only relation is has with templates (except for the
funny name) is that it will be used instead of a template instantiation
if the template is to be instantiated on the specialization type.
Secondly, if there is a problem with the paragraph in §14/3 that you
cite, it is that it includes explicit instantiation; an explicit
instantiation is a class definition, and if
struct S {} s, *p;
is legal,
template<> struct T<int> {} s, *p;
should be too. (I would argue against allowing either, but that train
has already left the station, and since C allows the first, we're stuck
with it.)
Otherwise, the statement in §14/3 is a bit irrelevant. A function
template must have exactly one declarator, and a class template exactly
zero; there's no need to try to englobe them both in some "at most one"
gobbledygook. (If I were designing the language from scratch, I'd not
allow any declarator in a declaration which defined a class or enum
type. But again, it's too late for that.)
And I agree that it's a bother:
template<> struct T<int> {}; // Requires a ';'
template<> void f<int>() {} // ';' forbidden
(At least C++11 will allow a semicolon after the function definition.)
Explicit specialization and explicit instantiation do not declare a template. They declare a template-id which refers to a specialization, which is a class.
However, this doesn't validate my example. The problem is that everything declared following template or template<> is part of the explicit instantiation or specialization, respectively. Only certain types of entities may be specialized or instantiated, and previously-undeclared names aren't one of them.
Consider these examples making gratuitous, but legal use of elaborated-type-specifiers (§7.1.5.3):
template< typename T > struct s;
template< typename T > s< int > *f() {}
template<> struct u *f< char >(); // struct u is declared
u *p = 0; // see, we can use its name now.
template<> struct s< int > *f< int >(); // s<int> declared but not specialized
template struct s< int > *f< long >(); // s<int> declared but not instantiated
As far as I can tell, the Standard is fuzzy about specifying which declared name is the one specialized. The language does weakly imply that each such declaration applies to only one template: §14.7.2/2
If the explicit instantiation is for a class, a function or a member template specialization…
and §14.7.3/2
An explicit specialization shall be declared in the namespace of which the template is a member…
The only way to resolve this is to ignore the type declaration if the declarator also specifies a legal instantiation/specialization.
Getting to the point, the examples in the question specify illegal specializations in the declarator and then expect the compiler to backtrack and specialize the type instead. Given the explicit lists of what specializations and declarations are allowed to do in §14.7.2/1 and §14.7.3/1, it seems more reasonable to complain about template<> struct t< int > {} r; that r is not a function template, member function template, static data member of a class template, etc.
template<class A,class B>
void tmp(){
set<int,int>::iterator it; //works
set<A,B>::iterator it; // doesn't work
}
Due to some rather annoying limitations in C++'s grammar, you must explicitly tell C++ that set<A,B>::iterator is a type name, rather than a static member identifier, using the typename keyword. For example, this code compiles just fine:
#include <set>
template<class A, class B>
void tmp() {
std::set<int,int>::iterator x; // OK
typename std::set<A,B>::iterator it; // Also OK
}
int main() {
tmp<int,int>();
return 0;
}
This occurs because C++ requires that the compiler make a final decision as to whether to interpret set<A,B>::iterator as a type or as a variable/function when it's parsing the grammar; before the template is instantiated. However, prior to template instantiation, it is impossible to make that determination, as in the general case this may depend on the values of A and B. As such, the compiler will assume it to be a variable/function unless explicitly stated otherwise. This then results in a parse error.
OK, suppose I want to check whether the template parameter has a nested type/typedef XYZ.
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
template <class U>
static yes f(typename U::XYZ*);
template <class /*U*/>
static no f(...);
enum {value = sizeof(f<T>(0))==sizeof(yes)};
};
Works fine, as expected.
Now consider this:
template <class T>
struct hasXZY
{
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(typename T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
hasXYZ<int> now results in a compile-time error. OK, f is not a template function. But on the other hand when hasXYZis instantiated for int via hasXYZ<int>::value, the compiler could easily just exclude f(int::XYZ*) from candidate list. I just don't understand why a failure in the instantiation of a member functions declaration in a class template must make the whole class instantiation fail. Any ideas?
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
SFINAE is used only when creating a candidate set for a function overload resolution. In your first example, you are calling the overloaded f() function, and the first one is excluded thanks to SFINAE.
In your second example, when instantiate hasXZY, all its members must be well defined, and the substitution of the template parameter must not fail. It does for int::XYZ.
Members will not be excluded from the class because of a substitution failure.
I'm not a C++ language lawyer, but I'll have a go at this.
In your second example, the member functions must be well-defined because they are no longer template functions once hasXZY is instantiated for int. To convince yourself of this, do the substitution for T "by hand":
struct hasXYZ
{
typedef int T;
typedef char no;
typedef struct { char x[2]; } yes;
static yes f(T::XYZ*);
static no f(...);
enum {value = sizeof(f(0))==sizeof(yes)};
};
int main()
{
std::cout << hasXYZ::value << "\n";
}
and observe that this fails to compile, with the same compiler error as before (in GCC, at least):
foo.cc:9: error: ‘T’ is not a class or namespace
By contrast, the first example compiles and behaves as expected after manual instantiation; the f members are still templated on U.
Edit: My question is: why should the member function declararions be all well-formed? Since the compiler instantiates the methods only upon their usage, why does it need correct declaration. Consider the above example2 as a possible use-case of this feature.
When implicitly instantiating a class template specialization, the compiler has to inspect the complete declarator of that member because it needs to know basic information about the declaration. Such can contribute to the size of the class template specialization.
If inspecting the declaration part will find out it's declaring a data-member, the sizeof value of the class will possibly yield a different value. If you would have declared a function pointer instead, this would be the case
yes (*f)(typename T::XYZ*);
The C++ language is defined in such a way that the type of a declaration is known only once the whole declaration is parsed.
You can argue that you put static there, and thus in this case this is not needed to compute its size. But it is needed for name-lookup to know what a name hasXZY<T>::f refers to and that there was declared a name f at all. The compiler will not instantiate the definition of hasXYZ::f, but it will only instantiate the non-definition part of the declaration, to gets its type and adding its name to the class type for name lookup purposes. I believe supporting delayed-instantiation for declaration of names in particular cases where it would possibly work would complicate implementation of C++ compilers and the C++ spec even more, for no comparable benefit.
And finally, in your example where you attempt to call it, the compiler has to instantiate the declaration, because it needs to lookup the name f, and for this it needs to know whether that declaration is a function or something else. So I really even theoretically can't see a way your example could work without instantiating the declaration. Note that in any case, these will not instantiate a definition of the function.
I was reading the Wikipedia article on SFINAE and encountered following code sample:
struct Test
{
typedef int Type;
};
template < typename T >
void f( typename T::Type ) {} // definition #1
template < typename T >
void f( T ) {} // definition #2
void foo()
{
f< Test > ( 10 ); //call #1
f< int > ( 10 ); //call #2 without error thanks to SFINAE
}
Now I've actually written code like this before, and somehow intuitively I knew that I needed to type "typename T" instead of just "T". However, it would be nice to know the actual logic behind it. Anyone care to explain?
The short version that you need to do typename X::Y whenever X is or depends on a template parameter. Until X is known, the compiler can't tell if Y is a type or a value. So you have to add typename to specify that it is a type.
For example:
template <typename T>
struct Foo {
typename T::some_type x; // T is a template parameter. `some_type` may or may not exist depending on what type T is.
};
template <typename T>
struct Foo {
typename some_template<T>::some_type x; // `some_template` may or may not have a `some_type` member, depending on which specialization is used when it is instantiated for type `T`
};
As sbi points out in the comments, the cause of the ambiguity is that Y might be a static member, an enum or a function. Without knowing the type of X, we can't tell.
The standard specifies that the compiler should assume it is a value unless it is explicitly labelled a type by using the typename keyword.
And it sounds like the commenters really want me to mention another related case as well: ;)
If the dependant name is a function member template, and you call it with an explicit template argument (foo.bar<int>(), for example), you have to add the template keyword before the function name, as in foo.template bar<int>().
The reason for this is that without the template keyword, the compiler assumes that bar is a value, and you wish to invoke the less than operator (operator<) on it.
In general, C++'s syntax (inherited from C) has a technical defect: the parser MUST know whether something names a type, or not, otherwise it just can't solve certain ambiguities (e.g., is X * Y a multiplication, or the declaration of a pointer Y to objects of type X? it all depends on whether X names a type...!-). The typename "adjective" lets you make that perfectly clear and explicit when needed (which, as another answer mentions, is typical when template parameters are involved;-).
Basically, you need the typename keyword when you are writing template code (i.e. you are in a function template or class template) and you are referring to an indentifier that depends on a template parameter that might not be known to be a type, but must be interpreted as a type in your template code.
In your example, you use typename T::Type at definition #1 because T::Type depends on the template parameter T and might otherwise be a data member.
You don't need typename T at definition #2 as T is declared to be a type as part of the template definition.