I'm trying to write a generic function with an argument that contains multiple transformations on the template type, such as:
#include <iostream>
#include <string>
#include <type_traits>
template< typename _T_ >
void foo
(
const std::basic_string< typename std::remove_cv< typename std::remove_extent< _T_ >::type >::type > & str
)
{
std::cout << str << std::endl;
}
int main( void )
{
foo< char const [ 3 ] >( "abc" ); // OK
foo( "abc" ); // Cannot deduce template argument
return 0;
}
Unfortunately, the compiler is unable to deduce the correct type.
Tested with latest versions of Clang, GCC and MSVC.
Interestingly, it seems the compiler is able to infer with one transformation:
const std::basic_string< typename std::remove_extent< _T_ >::type > & str
Obviously, the example above fails, because of the const
, hence the need for remove_cv
after remove_extent
.
Is this expected, and is there any way to achieve this?
Complicated names containing qualified-ids are non-deduced contexts in C++. In
foo< char const [ 3 ] >( "abc" );
you supply the template argument T
. In
foo( "abc" );
the template argument T
cannot be deduced (function arguments are separate from template arguments, so T
will not be deduced from "abc"
).
One solution is to deduce the template argument first and then construct the basic_string
when the argument is a const CharT*
:
template <class CharT>
void foo(const std::basic_string<CharT>& string)
{
// ...
}
template <class CharT>
void foo(const CharT* p)
{
std::basic_string<CharT> s{p};
foo(s);
}
Another solution is to simply rely on class template argument deduction to handle both cases:
template <class Arg>
void foo(Arg&& arg)
{
std::basic_string s{std::forward<Arg>(arg)};
// ...
}