I am currently thinking about how to best constrain a generic type of a template to an std::sting
as well as string literals. Therefore I compare the deduced type with the desired type using std::is_same
. In case of an std::string
this works right away. For a string literal, meaning a char const array, it only works if I use std::decay
on the type and then compare the result to the type char const *
. If I directly compare the deduced type to what I think it should be, is_same
returns false, as is illustrated by the following example code.
template <class TYPE>
void function(TYPE&& parameter)
{
//this doesn't work as expected
std::cout << typeid(TYPE).name() << " : " << typeid(char const [5]).name() << std::endl;
std::cout << std::is_same<char const [5], TYPE>::value << std::endl;
//this works as expected
std::cout << typeid(std::decay_t<TYPE>).name() << " : " << typeid(char const *).name() << std::endl;
std::cout << std::is_same<char const *, std::decay_t<TYPE>>::value << std::endl;
}
int main(int argc, char** argv)
{
function("name");
return 0;
}
The output generated is the following:
char const [5] : char const [5]
0
char const * __ptr64 : char const * __ptr64
1
Now, what I am wondering is why is_same
returns false in the first case even though the types appear to be identical.
The only possible explanation that I could come up with is that within the function std::is_same
a transformation similar to std::decay
is applied to the type (for instance a function call). But then again this transformation would also occur to the other type, yielding the same result and thus resulting in equality.
Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.
A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
Alex April 24, 2022, 7:49 pm August 24, 2022. Class template argument deduction (CTAD) C++17. Starting in C++17, when instantiating an object from a class template, the compiler can deduce the template types from the types of the object's initializer (this is called class template argument deduction or CTAD for short).
" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.
String literals are not passed by value as char const [N]
, but by reference as char const (&)[N]
.
This works correctly for me:
std::cout << std::is_same<char const (&)[5], TYPE>::value << std::endl;
Note here that
1) Refers to a
std::type_info
object representing the type type. If type is a reference type, the result refers to astd::type_info
object representing the referenced type.
You can easily verify that is_same
doesn't discard reference-ness in the same way as type_info
, for example by checking that
std::is_same<int&, int>::value == false
This explains why the typeid
name is the same, but your is_same
test still fails.
Using gcc custom function:
template < class T >
constexpr std::string type_name()
{
std::string p = __PRETTY_FUNCTION__;
return p.substr( 43 + 10, p.length() - 100 - 1 - 10 );
}
And adding it to your code:
std::cout << type_name<TYPE>() << " : " << type_name<char const [5]>() << std::endl;
The results are:
A5_c : A5_c
0
const char (&)[5] : const char [5]
So you need to use std::remove_reference
on TYPE
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With