From a practical point of view, I understand that both typedef and test are somewhat "superfluous" and need to be removed if we want the following code to compile:
template< typename type_t >
typedef struct tagTest
{
int a;
} test;
However, I thought that the set of typedef declarations was a subset of the set of declarations. They just happened to have that specific decl-specifier. That was my rationalization for
typedef struct tagTest
{
int a;
} test;
introducing the identifier test and declaring the structure tagTest. If that interpretation is correct, then the following paragraph from the standard should allow template typedef's (although not with the meaning given by the keyword using).
The declaration in a template-declaration shall
—
(1.1)
declare or define a function, a class, or a variable, or
—
(1.2)
define a member function, a member class, a member enumeration, or a static data member of a class
template or of a class nested within a class template, or
—
(1.3)
define a member template of a class or class template, or
—
(1.4)
be an alias-declaration.
I cannot see error in my reasoning, yet the conclusion is illegal.
What are the relevant parts of the standard that solve the above conundrum?
UPDATE
Part of the above reasoning uses the fact that typedef struct declares a structure. The typedef specifier, as far as I understand it, implies that any variables declared are really types. That is, the typedef upgrades test from a mere variable to a type that is equivalent to the declared tagTest. That is why the following code compiles (albeit with a warning).
typedef struct tagTest
{
int a;
};
tagTest t;
One of the answers takes care of the superfluous test. But, it is possible to use typedef without a declarator because "Init-declarator-list is optional when declaring a named class/struct/union or a named enumeration"
Template typedefs weren't allowed pre-C++11 and with C++11 template aliases were introduced to address those issues. Cfr. C++ template typedefs and wikipedia.
Since, as you noted, the standard doesn't allow typedef to be in there, the code is invalid
alias-declaration:
using identifier attribute-specifier-seqopt= type-id ;
typedef declarations are not alias declarations.
Furthermore you can't have a declarator if you're declaring a class template, it is explicitly forbidden by the standard
[temp]/p3
In a template-declaration, explicit specialization, or explicit instantiation the init-declarator-list in the declaration
shall contain at most one declarator. When such a declaration is used to declare a class template,
no declarator is permitted.
so not even the following will compile
template< typename type_t >
struct tagTest
{
int a;
} test;
Edit:
It is nowhere specified that
typedef struct S { };
should be an error, thus both gcc and clang accept it with a warning. I assume Clang counts on [temp]/3 to issue an error in case typedef was being used with a template while gcc rejects this code immediately
template<typename T>
typedef struct S { };
cfr. clang bug 22249
Independently from what the typedef defines, that is a typedef declaration, which is not listed in those cases:
[member] function
[member] class
variable
member enumeration
static data member of a class template/of a class nested within a class template
member template of a class or class template
alias declaration
And just to be clear typedef declarations are not alias declarations. Alias declaration, as specified by the grammar at §7 of the standard are:
alias-declaration:
using identifier attribute-specifier-seqopt= type-id ;
Not to mention that if this was possible, then template using declaration would not be nearly as "cool" as they are today, and there would be little to no sense to have both.
C does not support templates and the
typedef struct tagX {
} X;
syntax in C++ is vestigial C, there to allow continued support for C headers etc, not for use in actual C++.
The C++ syntax for the above is
struct X {};
(YMMV on brace placement)
Related
I came across elaborated type specifiers in a function parameter list. According to cppreference
the keyword class, struct, or union, followed by template name with template arguments (optionally qualified, optionally using template disambiguator), previously defined as the name of a class template.
the following would be valid C++ code:
template<class T>
struct Foo {};
struct Bar{
int Baz( struct Foo<class T> foo) {
return 5;
}
};
And indeed it compiles on the three major compilers. But I can't find a way how to call the function Bar::Baz, which seems reasonable, because it'd have to deduce T. To do this, it'd need to be a function template, which it isn't.
It obviously works when I change it to an explicit specialisation int Baz(struct Foo<int> foo).
What's the usecase for this?
Full example here.
How do I call a function with elaborated type specifier template?
In exactly the same way as you would call a function that didn't have an elaborated type specifier:
Bar b{};
Foo<T> f{};
b.Baz(f);
And here are declarations equivalent to yours without using elaborted type specifiers:
class T;
struct Bar{
int Baz(Foo<T> foo) {
return 5;
}
};
What's the usecase for this?
Elaborated type specifiers are used in C to refer to struct and union tags that don't have a type alias. Furthermore, they can be used to disambiguate a tag that conflicts with another name. They also implicitly behave as as struct / union declaration in a context where the declaration is being used. Some programmers dislike this and prefer a distinct declaration instead.
In C++, the first case isn't needed. The second case can be needed, although it's advisable to avoid such name conflicts when possible. Besides that, they are needed for cross-language compatibility.
Current C++ compilers (latest gcc, clang) require the typename keyword in the example below:
template<class T>
struct A
{
};
template<class T>
void f(T)
{
struct C
{
};
typedef typename A<C>::Type Type; // typename required
}
If typename is omitted gcc (4.9, 5.0) reports the error:
need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope
This example is otherwise well-formed according to my reading of the C++11 standard.
This behaviour seems to be covered by the following wording:
[temp.dep.type]/8
A type is dependent if it is
a template parameter,
a member of an unknown specialization,
a nested class or enumeration that is a member of the current instantiation,
a cv-qualified type where the cv-unqualified type is dependent,
a compound type constructed from any dependent type,
an array type constructed from any dependent type or whose size is specified by a constant expression
that is value-dependent,
a simple-template-id in which either the template name is a template parameter or any of the template
arguments is a dependent type or an expression that is type-dependent or value-dependent, or
denoted by decltype(expression), where expression is type-dependent.
However, according to [class.local] the class C is a local class rather than a nested class. If so, why should A<C> be treated as dependent?
EDIT
For bonus points, if the example is modified by adding a member enum to C as follows:
template<typename T>
struct A
{
typedef T Type;
};
template<class T>
void f(T)
{
struct C
{
enum { value = T::value };
};
typedef typename A<C>::Type Type; // typename required
}
Should A<C> now be treated as dependent?
According to my understanding (and the current wording of the standard), C in your example is not dependent. Neither is A<C>::Type, so the typename is not required.
There is a fundamental difference between nested classes of class templates and local classes in function templates: The latter cannot be specialized, thus any reference to a local class inside a function template is uniform. That is, in every specialization of f, C refers to the class C that is defined in this function template f. That is not the case with class templates as you can indeed explicitly specialize members on their own (as covered in [temp.expl.spec]
/(1.6)):
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };
However:
A type is dependent if it is
a compound type constructed from any dependent type,
So if the definition was done as in dyp's example, C would be dependent as it is constructed from T.
There are unclarities in the standards wording that are being discussed in the comment section, e.g. about definitions of member functions that depend on T and how that transposes to the classes dependency.
Following is my reasoning, hope it helps. The local C does not instantiate until f instantiate. So, A<C> is not an instantiation and is opaque to the compiler when it sees it. Because of the opaqueness, the compiler cannot determine whether A<C>::Type is a nested type name or a data member or a method. However, by default, the compiler does not see A<C>::Type as a nested type name. Therefore, an explicit specification is needed.
There doesn't appear to be anything in the standard to state that the typename keyword should be necessary here. The wording does not explicitly state otherwise, either, which may have led GCC to take a bit of a shortcut in treating f<T>(T)::C (being a local class in a function template specialisation) as dependent on T — by extension, this would make A<[f<T>(T)::]C>::Type dependent.
Core defect 1484 wasn't raised for this issue specifically, but I think the additional non-normative text it proposes makes the intention clear and, were it in a standard, GCC would compliantly not require the typename keyword here.
I know that in C++ we can do this:
class A {} a;
This makes an object of type A named a. It's equivalent to:
A a;
I was wondering how I would do this with templates. For example:
template <typename T> struct N {} <int> n;
This doesn't compile, but you get the idea. How would I specify the template arguments to an object created inline with its class definition? Is this even possible?
The stuff after the closing } is called an init-declarator-list according to the standard.
14.3 explicitly forbids them to be used in template class declarations:
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.
I don't think you can do that. The form you mentioned, for structures and classes is kept, from my understanding, for backward compatibility with c - where you could do that for structs.
Nice idea, though :)
You can't declare variables from a template definition, not even if all template arguments have defaults.
This also is an error:
template <typename T = int> struct N {} n;
http://ideone.com/vFlIEg
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.
In C++, is there any difference between:
struct Foo { ... };
and:
typedef struct { ... } Foo;
In C++, there is only a subtle difference. It's a holdover from C, in which it makes a difference.
The C language standard (C89 §3.1.2.3, C99 §6.2.3, and C11 §6.2.3) mandates separate namespaces for different categories of identifiers, including tag identifiers (for struct/union/enum) and ordinary identifiers (for typedef and other identifiers).
If you just said:
struct Foo { ... };
Foo x;
you would get a compiler error, because Foo is only defined in the tag namespace.
You'd have to declare it as:
struct Foo x;
Any time you want to refer to a Foo, you'd always have to call it a struct Foo. This gets annoying fast, so you can add a typedef:
struct Foo { ... };
typedef struct Foo Foo;
Now struct Foo (in the tag namespace) and just plain Foo (in the ordinary identifier namespace) both refer to the same thing, and you can freely declare objects of type Foo without the struct keyword.
The construct:
typedef struct Foo { ... } Foo;
is just an abbreviation for the declaration and typedef.
Finally,
typedef struct { ... } Foo;
declares an anonymous structure and creates a typedef for it. Thus, with this construct, it doesn't have a name in the tag namespace, only a name in the typedef namespace. This means it also cannot be forward-declared. If you want to make a forward declaration, you have to give it a name in the tag namespace.
In C++, all struct/union/enum/class declarations act like they are implicitly typedef'ed, as long as the name is not hidden by another declaration with the same name. See Michael Burr's answer for the full details.
In this DDJ article, Dan Saks explains one small area where bugs can creep through if you do not typedef your structs (and classes!):
If you want, you can imagine that C++
generates a typedef for every tag
name, such as
typedef class string string;
Unfortunately, this is not entirely
accurate. I wish it were that simple,
but it's not. C++ can't generate such
typedefs for structs, unions, or enums
without introducing incompatibilities
with C.
For example, suppose a C program
declares both a function and a struct
named status:
int status(); struct status;
Again, this may be bad practice, but
it is C. In this program, status (by
itself) refers to the function; struct
status refers to the type.
If C++ did automatically generate
typedefs for tags, then when you
compiled this program as C++, the
compiler would generate:
typedef struct status status;
Unfortunately, this type name would
conflict with the function name, and
the program would not compile. That's
why C++ can't simply generate a
typedef for each tag.
In C++, tags act just like typedef
names, except that a program can
declare an object, function, or
enumerator with the same name and the
same scope as a tag. In that case, the
object, function, or enumerator name
hides the tag name. The program can
refer to the tag name only by using
the keyword class, struct, union, or
enum (as appropriate) in front of the
tag name. A type name consisting of
one of these keywords followed by a
tag is an elaborated-type-specifier.
For instance, struct status and enum
month are elaborated-type-specifiers.
Thus, a C program that contains both:
int status(); struct status;
behaves the same when compiled as C++.
The name status alone refers to the
function. The program can refer to the
type only by using the
elaborated-type-specifier struct
status.
So how does this allow bugs to creep
into programs? Consider the program in
Listing 1. This program defines a
class foo with a default constructor,
and a conversion operator that
converts a foo object to char const *.
The expression
p = foo();
in main should construct a foo object
and apply the conversion operator. The
subsequent output statement
cout << p << '\n';
should display class foo, but it
doesn't. It displays function foo.
This surprising result occurs because
the program includes header lib.h
shown in Listing 2. This header
defines a function also named foo. The
function name foo hides the class name
foo, so the reference to foo in main
refers to the function, not the class.
main can refer to the class only by
using an elaborated-type-specifier, as
in
p = class foo();
The way to avoid such confusion
throughout the program is to add the
following typedef for the class name
foo:
typedef class foo foo;
immediately before or after the class
definition. This typedef causes a
conflict between the type name foo and
the function name foo (from the
library) that will trigger a
compile-time error.
I know of no one who actually writes
these typedefs as a matter of course.
It requires a lot of discipline. Since
the incidence of errors such as the
one in Listing 1 is probably pretty
small, you many never run afoul of
this problem. But if an error in your
software might cause bodily injury,
then you should write the typedefs no
matter how unlikely the error.
I can't imagine why anyone would ever
want to hide a class name with a
function or object name in the same
scope as the class. The hiding rules
in C were a mistake, and they should
not have been extended to classes in
C++. Indeed, you can correct the
mistake, but it requires extra
programming discipline and effort that
should not be necessary.
One more important difference: typedefs cannot be forward declared. So for the typedef option you must #include the file containing the typedef, meaning everything that #includes your .h also includes that file whether it directly needs it or not, and so on. It can definitely impact your build times on larger projects.
Without the typedef, in some cases you can just add a forward declaration of struct Foo; at the top of your .h file, and only #include the struct definition in your .cpp file.
There is a difference, but subtle. Look at it this way: struct Foo introduces a new type. The second one creates an alias called Foo (and not a new type) for an unnamed struct type.
7.1.3 The typedef specifier
1 [...]
A name declared with the typedef specifier becomes a typedef-name. Within the scope of its declaration, a
typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier in
the way described in Clause 8. A typedef-name is thus a synonym for another type. A typedef-name does not introduce a new type the way a class declaration (9.1) or enum declaration does.
8 If the typedef declaration defines an unnamed class (or enum), the first typedef-name declared by the declaration
to be that class type (or enum type) is used to denote the class type (or enum type) for linkage
purposes only (3.5). [ Example:
typedef struct { } *ps, S; // S is the class name for linkage purposes
So, a typedef always is used as an placeholder/synonym for another type.
You can't use forward declaration with the typedef struct.
The struct itself is an anonymous type, so you don't have an actual name to forward declare.
typedef struct{
int one;
int two;
}myStruct;
A forward declaration like this wont work:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
An important difference between a 'typedef struct' and a 'struct' in C++ is that inline member initialisation in 'typedef structs' will not work.
// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;
// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };
There is no difference in C++, but I believe in C it would allow you to declare instances of the struct Foo without explicitly doing:
struct Foo bar;
Struct is to create a data type.
The typedef is to set a nickname for a data type.