Templated Default Arguments in C++ Member Functions

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Templated Default Arguments in C++ Member Functions

Colin A. Smith
Hello. I just started trying to get Clang to compile a rather large piece of scientific code and ran into a problem that I'm not sure is a bug or a violation of the C++ spec. The codebase uses smart-pointers which are templated on classes that are subclasses of a reference counted class (like Boost intrusive_ptr). To cut down on compile time, many of those subclasses are forward declared, which Clang handles great. The problem comes when one of those forward declared subclasses is used as an argument in a member function and given a default value. A very stripped down snippet of code which reproduces the error is the following:

template< typename T > class PointerClass {
public:
        PointerClass( T * object_p ) : p_( object_p ) {
                p_->acquire();
        }
private:
        T * p_;
};

class ExternallyImplementedClass;

class MyClass {
        void foo( PointerClass<ExternallyImplementedClass> = 0 );
};

int main(void) {
        return 0;
}

This compiles fine with gcc (and probably Visual C++), but produces an error with Clang. The error goes away if the "= 0" is removed. The error produced is the following:

clang_test.cc:4:5: error: member access into incomplete type 'ExternallyImplementedClass'
                p_->acquire();
                  ^
clang_test.cc:13:55: note: in instantiation of member function 'PointerClass<ExternallyImplementedClass>::PointerClass' requested here
        void foo( PointerClass<ExternallyImplementedClass> = 0 );
                                                             ^
clang_test.cc:10:7: note: forward declaration of 'ExternallyImplementedClass'
class ExternallyImplementedClass;
      ^
1 error generated.

Because the foo function is never used and its implementation would be in another file, I'm not sure why PointerClass<ExternallyImplementedClass> would be getting instantiated. When a piece of code would be using foo, it would have access to the full header for ExternallyImplementedClass and make instantiation possible. I read Doug Gregor's great blog post about Two-Phase Name Lookup, which helped explain some other errors we were seeing. Since I'm not a C++ expert, it would be nice to know if this is another place where Clang is implementing the C++ spec and gcc/Visual C++ are a bit looser. If that isn't the case, I'll definitely add this to Bugzilla. I don't know if I'm up to the task of fixing it myself.

Cheers.

-Colin
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Templated Default Arguments in C++ Member Functions

Douglas Gregor

On Sep 8, 2010, at 11:28 PM, Colin A. Smith wrote:

> Hello. I just started trying to get Clang to compile a rather large piece of scientific code and ran into a problem that I'm not sure is a bug or a violation of the C++ spec. The codebase uses smart-pointers which are templated on classes that are subclasses of a reference counted class (like Boost intrusive_ptr). To cut down on compile time, many of those subclasses are forward declared, which Clang handles great. The problem comes when one of those forward declared subclasses is used as an argument in a member function and given a default value. A very stripped down snippet of code which reproduces the error is the following:
>
> template< typename T > class PointerClass {
> public:
> PointerClass( T * object_p ) : p_( object_p ) {
> p_->acquire();
> }
> private:
> T * p_;
> };
>
> class ExternallyImplementedClass;
>
> class MyClass {
> void foo( PointerClass<ExternallyImplementedClass> = 0 );
> };
>
> int main(void) {
> return 0;
> }
>
> This compiles fine with gcc (and probably Visual C++), but produces an error with Clang. The error goes away if the "= 0" is removed. The error produced is the following:
>
> clang_test.cc:4:5: error: member access into incomplete type 'ExternallyImplementedClass'
>                p_->acquire();
>                  ^
> clang_test.cc:13:55: note: in instantiation of member function 'PointerClass<ExternallyImplementedClass>::PointerClass' requested here
>        void foo( PointerClass<ExternallyImplementedClass> = 0 );
>                                                             ^
> clang_test.cc:10:7: note: forward declaration of 'ExternallyImplementedClass'
> class ExternallyImplementedClass;
>      ^
> 1 error generated.
>
> Because the foo function is never used and its implementation would be in another file, I'm not sure why PointerClass<ExternallyImplementedClass> would be getting instantiated. When a piece of code would be using foo, it would have access to the full header for ExternallyImplementedClass and make instantiation possible. I read Doug Gregor's great blog post about Two-Phase Name Lookup, which helped explain some other errors we were seeing. Since I'm not a C++ expert, it would be nice to know if this is another place where Clang is implementing the C++ spec and gcc/Visual C++ are a bit looser. If that isn't the case, I'll definitely add this to Bugzilla. I don't know if I'm up to the task of fixing it myself.

This is definitely a bug in Clang. We're not treating default arguments as unevaluated contexts, so we perform template instantiation when we shouldn't. Could you file this as a bug against Clang?

        - Doug
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev