Why is this constructor not giving an incomplete type error?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
12
down vote

favorite
3












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 is this working if the constructor is in cpp?
std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));
std::cout << "Done..." << std::endl;

// 2. Why is this not working if the constructor call has 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 the comments my main question is why the constructor call is not giving an error "invalid use of incomplete type 'class TestImpl'...". For reference I am using GCC 5.2, with no specific flags.







share|improve this question


















  • 5




    Is it really incomplete at the point of template instantiation?
    – Evg
    Aug 20 at 13:27






  • 1




    The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
    – Marek R
    Aug 20 at 13:32







  • 2




    Not reproducible.
    – n.m.
    Aug 20 at 13:43






  • 1




    I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
    – StoryTeller
    Aug 20 at 13:44






  • 2




    @StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
    – V0ldek
    Aug 20 at 13:48















up vote
12
down vote

favorite
3












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 is this working if the constructor is in cpp?
std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));
std::cout << "Done..." << std::endl;

// 2. Why is this not working if the constructor call has 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 the comments my main question is why the constructor call is not giving an error "invalid use of incomplete type 'class TestImpl'...". For reference I am using GCC 5.2, with no specific flags.







share|improve this question


















  • 5




    Is it really incomplete at the point of template instantiation?
    – Evg
    Aug 20 at 13:27






  • 1




    The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
    – Marek R
    Aug 20 at 13:32







  • 2




    Not reproducible.
    – n.m.
    Aug 20 at 13:43






  • 1




    I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
    – StoryTeller
    Aug 20 at 13:44






  • 2




    @StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
    – V0ldek
    Aug 20 at 13:48













up vote
12
down vote

favorite
3









up vote
12
down vote

favorite
3






3





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 is this working if the constructor is in cpp?
std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));
std::cout << "Done..." << std::endl;

// 2. Why is this not working if the constructor call has 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 the comments my main question is why the constructor call is not giving an error "invalid use of incomplete type 'class TestImpl'...". For reference I am using GCC 5.2, with no specific flags.







share|improve this question














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 is this working if the constructor is in cpp?
std::unique_ptr<TestImpl> pimpl(new TestImpl(std::forward<T>(Args)...));
std::cout << "Done..." << std::endl;

// 2. Why is this not working if the constructor call has 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 the comments my main question is why the constructor call is not giving an error "invalid use of incomplete type 'class TestImpl'...". For reference I am using GCC 5.2, with no specific flags.









share|improve this question













share|improve this question




share|improve this question








edited Aug 29 at 22:12









pfx

3,13981630




3,13981630










asked Aug 20 at 13:25









Kapil

765515




765515







  • 5




    Is it really incomplete at the point of template instantiation?
    – Evg
    Aug 20 at 13:27






  • 1




    The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
    – Marek R
    Aug 20 at 13:32







  • 2




    Not reproducible.
    – n.m.
    Aug 20 at 13:43






  • 1




    I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
    – StoryTeller
    Aug 20 at 13:44






  • 2




    @StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
    – V0ldek
    Aug 20 at 13:48













  • 5




    Is it really incomplete at the point of template instantiation?
    – Evg
    Aug 20 at 13:27






  • 1




    The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
    – Marek R
    Aug 20 at 13:32







  • 2




    Not reproducible.
    – n.m.
    Aug 20 at 13:43






  • 1




    I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
    – StoryTeller
    Aug 20 at 13:44






  • 2




    @StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
    – V0ldek
    Aug 20 at 13:48








5




5




Is it really incomplete at the point of template instantiation?
– Evg
Aug 20 at 13:27




Is it really incomplete at the point of template instantiation?
– Evg
Aug 20 at 13:27




1




1




The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
– Marek R
Aug 20 at 13:32





The reason is that yo used constructor in template, and template is instantiated when it is used and at that point full definition of TestImpl is know to compiler.
– Marek R
Aug 20 at 13:32





2




2




Not reproducible.
– n.m.
Aug 20 at 13:43




Not reproducible.
– n.m.
Aug 20 at 13:43




1




1




I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
– StoryTeller
Aug 20 at 13:44




I tried to reproduce but I can't. GCC 5.2 on Wandbox rejects it. The TU is laid out exactly like your sample would be.
– StoryTeller
Aug 20 at 13:44




2




2




@StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
– V0ldek
Aug 20 at 13:48





@StoryTeller Yes, and your sample works with the constructor, but does not work on the sayHello method - the exact unexpected behavior the question is about. Same goes for @n.m. .
– V0ldek
Aug 20 at 13:48













1 Answer
1






active

oldest

votes

















up vote
10
down vote



accepted










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






share|improve this answer






















  • 8.5.1 is more straightforward.
    – xskxzr
    Aug 20 at 14:16










  • @xskxzr - It is. But I stopped reading at Note :). Will add it.
    – StoryTeller
    Aug 20 at 14:16










  • The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
    – Oliv
    Aug 20 at 15:07










  • @Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
    – StoryTeller
    Aug 20 at 15:11










  • @Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
    – Passer By
    Aug 20 at 15:17











Your Answer





StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51931749%2fwhy-is-this-constructor-not-giving-an-incomplete-type-error%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
10
down vote



accepted










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






share|improve this answer






















  • 8.5.1 is more straightforward.
    – xskxzr
    Aug 20 at 14:16










  • @xskxzr - It is. But I stopped reading at Note :). Will add it.
    – StoryTeller
    Aug 20 at 14:16










  • The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
    – Oliv
    Aug 20 at 15:07










  • @Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
    – StoryTeller
    Aug 20 at 15:11










  • @Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
    – Passer By
    Aug 20 at 15:17















up vote
10
down vote



accepted










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






share|improve this answer






















  • 8.5.1 is more straightforward.
    – xskxzr
    Aug 20 at 14:16










  • @xskxzr - It is. But I stopped reading at Note :). Will add it.
    – StoryTeller
    Aug 20 at 14:16










  • The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
    – Oliv
    Aug 20 at 15:07










  • @Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
    – StoryTeller
    Aug 20 at 15:11










  • @Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
    – Passer By
    Aug 20 at 15:17













up vote
10
down vote



accepted







up vote
10
down vote



accepted






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






share|improve this answer














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







share|improve this answer














share|improve this answer



share|improve this answer








edited Aug 20 at 15:07









Passer By

8,52631953




8,52631953










answered Aug 20 at 14:08









StoryTeller

82.3k12163228




82.3k12163228











  • 8.5.1 is more straightforward.
    – xskxzr
    Aug 20 at 14:16










  • @xskxzr - It is. But I stopped reading at Note :). Will add it.
    – StoryTeller
    Aug 20 at 14:16










  • The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
    – Oliv
    Aug 20 at 15:07










  • @Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
    – StoryTeller
    Aug 20 at 15:11










  • @Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
    – Passer By
    Aug 20 at 15:17

















  • 8.5.1 is more straightforward.
    – xskxzr
    Aug 20 at 14:16










  • @xskxzr - It is. But I stopped reading at Note :). Will add it.
    – StoryTeller
    Aug 20 at 14:16










  • The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
    – Oliv
    Aug 20 at 15:07










  • @Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
    – StoryTeller
    Aug 20 at 15:11










  • @Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
    – Passer By
    Aug 20 at 15:17
















8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16




8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16












@xskxzr - It is. But I stopped reading at Note :). Will add it.
– StoryTeller
Aug 20 at 14:16




@xskxzr - It is. But I stopped reading at Note :). Will add it.
– StoryTeller
Aug 20 at 14:16












The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
– Oliv
Aug 20 at 15:07




The standard wording in [temp.dep] make me curious: In an expression of the form: postfix-expression ( expression-listopt ). It is not said in In a function-call expression:[...]. I wonder what is the "intent" of the standard here?
– Oliv
Aug 20 at 15:07












@Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
– StoryTeller
Aug 20 at 15:11




@Oliv - A functor object would fit the form but won't be a function call expression per-se, I think. Not sure however.
– StoryTeller
Aug 20 at 15:11












@Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
– Passer By
Aug 20 at 15:17





@Oliv Postfix-expressions that are only unqualified-ids includes much more than just function calls, stuff like functors, creating temporaries with type names, template names and whatnot.
– Passer By
Aug 20 at 15:17


















 

draft saved


draft discarded















































 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51931749%2fwhy-is-this-constructor-not-giving-an-incomplete-type-error%23new-answer', 'question_page');

);

Post as a guest













































































Comments

Popular posts from this blog

List of Gilmore Girls characters

What does second last employer means? [closed]

One-line joke