Is this code legal under C++14/17
?
template <class T1, class T2 >
class Foo
{
public:
class sentry;
};
template <class T1,class T2 = int>
class Foo<T1,T2>::sentry
{
public:
~sentry() { }
};
It compiles with GCC 4.9.3 but fails with GCC 5.3. Online demo
How can I fix this for GCC 5.3?
You cannot forward declare a nested structure outside the container. You can only forward declare it within the container.
You can declare default arguments for a template only for the first declaration of the template. If you want allow users to forward declare a class template, you should provide a forwarding header. If you want to forward declare someone else's class template using defaults, you are out of luck!
You will usually want to use forward declaration in a classes header file when you want to use the other type (class) as a member of the class. You can not use the forward-declared classes methods in the header file because C++ does not know the definition of that class at that point yet.
A forward declaration tells the compiler about the existence of an entity before actually defining the entity. Forward declarations can also be used with other entity in C++, such as functions, variables and user-defined types.
It's ill-formed according to [temp.param]/9 (emphasis mine):
A default template-argument is a template-argument ([temp.arg]) specified after = in a template-parameter. A default template-argument may be specified for any kind of template-parameter (type, non-type, template) that is not a template parameter pack ([temp.variadic]). A default template-argument may be specified in a template declaration. A default template-argument shall not be specified in the template-parameter-lists of the definition of a member of a class template that appears outside of the member's class. A default template-argument shall not be specified in a friend class template declaration. If a friend function template declaration specifies a default template-argument, that declaration shall be a definition and shall be the only declaration of the function template in the translation unit.
sentry
is a member class of Foo
. You defined it outside the class, and so it may not specify a default argument for the parameters of Foo
. As a general rule of thumb, default arguments should appear only on the primary template declaration.
This rule of thumb is also how your code may be fixed:
template <class T1, class T2 = int>
class Foo
{
public:
class sentry;
};
template <class T1,class T2>
class Foo<T1,T2>::sentry
{
public:
~sentry() { }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With