Let's assume that we have this small code:
template<typename T>
struct Test {
Test(T t) : m_t(t) {}
T m_t;
};
int main() {
Test t = 1;
}
This code easily compiles with [T=int]
for Test
class. Now if I write a code like this:
template<typename T>
struct Test {
Test(T t) : m_t(t) {}
T m_t;
};
struct S {
Test t = 1;
};
int main() {
S s;
}
This code fails to compile with the following error:
invalid use of template-name 'Test' without an argument list
I need to write it like Test<int> t = 1;
as a class member to work. Any idea why this happens?
CodePudding user response:
The reason
struct S {
Test t = 1;
};
does not work is because you aren't actually doing Test t = 1;
. An in class initializer is just a convenient way to tell the compiler what value to initialize t
with when one is not provided. What "actually" gets generated is
struct S {
S() : t(1) {} // created by the compiler
Test t;
};
and here you can more easily see that t
isn't specified with an initializer until you call the constructor.
CodePudding user response:
There is a difference between your two snippets - first Test t = 1
declares, defines, and initializes a new variable while the second only declares a member variable and specifies how it might be initialized.
The default member initializer is relevant only in the context of a constructor without t
in its member initializer list and there can easily be multiple constructors, each initializing t
in different way.
The following is valid C , what should type of t
be deduced to?
struct S {
Test t = 1;
S(){}
S(int):t(1){}
S(double):t(true){}
};
If this were to be supported, you hit the implementation issue of making type/size/layout of the class dependent on the definition of constructors which are likely in different translation units. Therefore it would make it impossible to define include classes such as S
(if one moved the definitions to some .cpp) via header files.