Вывод аргумента шаблона с несколькими преобразованиями - PullRequest
3 голосов
/ 10 февраля 2020

Я пытаюсь написать обобщенную c функцию с аргументом, который содержит несколько преобразований для типа шаблона, например:

#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;
}

К сожалению, компилятор не может вывести правильный тип .
Протестировано с последними версиями Clang, G CC и MSV C.

Интересно, что компилятор может вывести одно преобразование:

 const std::basic_string< typename std::remove_extent< _T_ >::type > & str

Очевидно, что приведенный выше пример терпит неудачу из-за const, отсюда и необходимость remove_cv после remove_extent.

Ожидается ли это, и есть ли способ достичь этого?

Ответы [ 2 ]

2 голосов
/ 10 февраля 2020

Сложные имена, содержащие квалифицированный идентификатор s, представляют собой не выведенные контексты в C ++. В

foo< char const [ 3 ] >( "abc" );

вы указываете аргумент шаблона T. В

foo( "abc" );

аргумент шаблона T не может быть выведен (аргументы функции отделены от аргументов шаблона, поэтому T не будет выведен из "abc").

Одно решение состоит в том, чтобы сначала вывести аргумент шаблона, а затем создать basic_string, когда аргумент является 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);
}

Другое решение - просто полагаться на дедукцию аргумента шаблона класса для обработки обоих случаев:

template <class Arg>
void foo(Arg&& arg)
{
    std::basic_string s{std::forward<Arg>(arg)};
    // ...
}
0 голосов
/ 10 февраля 2020

Возможно, вы можете создать тип в списке параметров шаблона и взять T в качестве ссылки в списке параметров функции

template<typename T, typename U = const std::basic_string<std::remove_cv_t<std::remove_extent_t<T>>>>
void foo
(
  T& t // deducible context
)
{
  U& u = t;
  std::cout << u << std::endl;
}

Godbolt demo

...