Why is this constructor not giving an incomplete type error?
Clash Royale CLAN TAG#URR8PPP
up vote
12
down vote
favorite
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.
c++ types language-lawyer
 |Â
show 11 more comments
up vote
12
down vote
favorite
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.
c++ types language-lawyer
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 ofTestImpl
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 thesayHello
method - the exact unexpected behavior the question is about. Same goes for @n.m. .
– V0ldek
Aug 20 at 13:48
 |Â
show 11 more comments
up vote
12
down vote
favorite
up vote
12
down vote
favorite
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.
c++ types language-lawyer
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.
c++ types language-lawyer
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 ofTestImpl
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 thesayHello
method - the exact unexpected behavior the question is about. Same goes for @n.m. .
– V0ldek
Aug 20 at 13:48
 |Â
show 11 more comments
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 ofTestImpl
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 thesayHello
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
 |Â
show 11 more comments
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
8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16
@xskxzr - It is. But I stopped reading atNote
:). 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
 |Â
show 6 more comments
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
8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16
@xskxzr - It is. But I stopped reading atNote
:). 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
 |Â
show 6 more comments
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
8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16
@xskxzr - It is. But I stopped reading atNote
:). 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
 |Â
show 6 more comments
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
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
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 atNote
:). 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
 |Â
show 6 more comments
8.5.1 is more straightforward.
– xskxzr
Aug 20 at 14:16
@xskxzr - It is. But I stopped reading atNote
:). 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
 |Â
show 6 more comments
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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