Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Forward declaration of a class nested in in a class template, is it legal?

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?

like image 635
Violet Giraffe Avatar asked Feb 17 '19 11:02

Violet Giraffe


People also ask

Can I forward declare a nested class?

You cannot forward declare a nested structure outside the container. You can only forward declare it within the container.

Can you forward declare a template class?

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!

When can I use forward declaration?

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.

What is forward declaration and where we can use this?

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.


Video Answer


1 Answers

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() { }
};
like image 169
StoryTeller - Unslander Monica Avatar answered Oct 09 '22 05:10

StoryTeller - Unslander Monica