Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template Argument Deduction from String Literal

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.

like image 317
bweber Avatar asked Feb 23 '17 13:02

bweber


People also ask

What is template argument deduction?

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.

What is template argument in C++?

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.

What is CTAD C++?

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).

What is Typename C++?

" 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.


2 Answers

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 a std::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.

like image 105
Useless Avatar answered Nov 10 '22 12:11

Useless


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.

like image 23
xinaiz Avatar answered Nov 10 '22 13:11

xinaiz