Reputation: 1312
In the following code, Get()
returns the default value of the template type. I was wondering why and how this is correct/defined for pointer types
#include <iostream>
#include <string>
template <typename ValueType>
inline ValueType Get()
{
return ValueType();
}
int main()
{
int* IntPtr = Get<int*>();
//int* IntPtr2 = (int*)(); // Invalid
//int* IntPtr3 = (int*){}; // Valid
std::cout << (IntPtr == nullptr ? "nullptr" : "non-nullptr") << std::endl;
std::cin.get();
return 0;
}
When the compiler evaluates ValueType()
in Get
, I would have expected it to become (int*)()
, but since this is invalid, is it treated differently?
Upvotes: 3
Views: 449
Reputation: 85371
When the compiler evaluates
ValueType()
inGet
, I would have expected it to become(int*)()
, but since this is invalid, is it treated differently?
A C++ template, while being very similar to a macro, does not perform a literal replacement. ValueType
remains an actual type within the scope of the template. So yes, return ValueType()
would be treated differently from (int*)()
, more like using ValueType = int*; return ValueType();
As to why using ValueType = int*; ValueType();
works when (int*)()
doesn't:
In C++, an expression of the form T()
(when T
is a type) is value-initialization syntax which creates a nameless object of type T
.
During value-initialization, non-class types are zero-initialized.
The problem is (int*)()
does not have the form T()
, but (T)()
. (int*)()
is parsed as a cast to int*
, but then it's missing the value to cast. Which is exactly what the compiler says in the error:
<source>:2:27: error: expected expression
int* IntPtr2 = (int*)();
^
For the same reason using T = int; int x = (T)();
also won't compile.
Similarly int* IntPtr3 = (int*){};
is also invalid C++ (GCC compiles it, but e.g. MSVC won't).
Some possible workarounds:
typedef
the pointer to some type, then you'll be able to use the T()
form normally:
using T = int*;
T ptr = T();
Use copy-list-initialization syntax:
int* ptr = {};
Use direct-list-initialization syntax:
int* ptr{};
Note that the direct-initialization form int* ptr();
is also unusable as it is subject to most vexing parse.
Upvotes: 2