Why incomplete type error not coming for constructor?

  • A+
Category:Languages

I have two files test.h and main.cpp as shown below :

test.h

#include <memory>  class TestImpl;  template <typename... T> void createConnection(T&&... Args) {     // 1. Why this is working if constructor is in cpp     std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));     std::cout << "Done..." << std::endl;      // 2. Why this is not working if constructor call have no issues     pimpl->sayHello(); } 

main.cpp

#include <iostream>  #include "test.h"  class TestImpl { public:     TestImpl(const std::string& first, const std::string& second)         : _first(first)         , _second(second)     {     }      void sayHello()     {         std::cout << "Hello ... " << std::endl;     }  private:     std::string _first;     std::string _second; };  int main() {     std::cout << "Hello World!" << std::endl;     createConnection("ABC", "DEF");     return 0; } 

As evident from comments my main question is why constructor call is not giving error "invalid use of incomplete type 'class TestImpl'..." and for information I am using compiler gcc 5.2 and no specific flags are used during compilation

 


Simply put, GCC doesn't have to reject your program, and Clang doesn't have to accept it. It's ill-formed, no diagnostic required. Since TestImpl is incomplete, your template is in violation of

[temp.res]/8

... The program is ill-formed, no diagnostic required, if:

  • a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
  • the interpretation of such a construct in the hypothetical instantiation is different from the interpretation of the corresponding construct in any actual instantiation of the template.

One could argue that the constructor being called is dependent, but the class name is surely not!

In our case, a hypothetical instantiation with a pack of two strings immediately after the template definition will give different results than at the point of instantiation in your program. This is because the class name itself (which is, again, not dependent) has different meaning in the two contexts.

It's not a valid template definition. But GCC is exercising some leeway here, since no diagnostic is required, and plowing on.


This is succinctly summarized in the note under the bullets, which while not normative, describes your case:

This can happen in situations including the following:

  • a type used in a non-dependent name is incomplete at the point at which a template is defined but is complete at the point at which an instantiation is performed, or

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: