Вопрос по c++11, c++, variadic-templates – Не может иметь typeof (std :: endl) в качестве параметра шаблона?

10

Итак, я пытался написать такую функцию:

void append_to_stream(std::ostream &stream)
{ }

template <typename T, typename... Args>
void append_to_stream(std::ostream &stream, T first, Args&&... rest)
{
  stream << first;
  append_to_stream(stream, rest...);
}

и назовите это как:

append_to_stream(stream, 
                 std::endl,
                 std::endl);

Но это не работает. Я получаю сообщение об ошибке "слишком много аргументов" к функции. Я сузил его до такой степени, что знаю, чтоstd::endl виновен - вероятно, потому что это функция. Мне удалось «решить» это путем объявления структуры под названиемendl и определить<<operator для того, чтобы он просто вызываетstd::endl, Это работает, но не особенно хорошо. Разве нельзя принять std :: endl в качестве аргумента шаблона? Функция работает для других типов.

Изменить: здесь ошибка:

src/log/sinks/file_sink.cpp:62:21: error: too many arguments to function ‘void log::sinks::append_to_stream(std::string&, Args&& ...) [with Args = {}, std::string = std::basic_string<char>]’

Update

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

  template<class e, class t, class a> 
  basic_ostream<e,t>&(*)(basic_ostream<e,t>&os) get_endl(basic_string<e,t,a>& s) 
  {
return std::endl<e,t>;
  }

Однако это не компилируется.

Ошибка:

src/log/sinks/file_sink.cpp:42:28: error: expected unqualified-id before ‘)’ token
src/log/sinks/file_sink.cpp:42:53: error: expected initializer before ‘get_endl’

Есть идеи почему? Ради компиляции я добавилusing namespace std;

Я озадачен тем, что ваши сообщения об ошибках показывают, что ваш потокstd::string? Это не соответствует тому, что вы сказали ... Mooing Duck
@MooingDuck Это случай утечки абстракции. Я попытался привести пример к основам - я по ошибке оставилstd::string аргумент в. Реальная функция обернута функцией, которая создаетfstream. Max
Какой компилятор вы используете? Некоторые компиляторы IIRC некоторое время испытывали проблемы с такой рекурсией. Flexo♦
std::endl это не функция, это шаблон. Bo Persson
@ Rob & # x1D69 ;: Компилятор ссылается на множество возможных специализацийendl, которые образуют набор перегруженных функций. Поскольку тип аргумента функции является общим, то любой из них будет совпадать, и компилятор не может выбирать из них. Если аргумент имел определенный тип (например,ostream&(*)(ostream&)), то компилятор может выбрать специализацию (endl<char, char_traits<char>>) который имеет такой тип; вот почемуostream << endl является действительным. Mike Seymour

Ваш Ответ

2   ответа
4

чем указание аргументов шаблона или определение целого нового шаблона (!), Разрешает перегрузку путем приведения.

typedef std::ostream & (&omanip_t)( std::ostream & );

append_to_stream(stream, 
                 static_cast< omanip_t >( std::endl ),
                 static_cast< omanip_t >( std::endl ) );

Это будет работать для всех манипуляторов, тогда как некоторые манипуляторы могут быть настроены по-разному, например, если они предоставлены пользователем.

Кроме того, вы должны пройтиT first либо совершенной пересылкой, либо константной ссылкой. Нет смысла сначала пересылать, а затем передавать по значению. Также без звонкаstd::forwardаргументы rvalue будут переданы по значению & # x2026; просто следуя идиоме, было бы

template <typename T, typename... Args>
void append_to_stream(std::ostream &stream, T &&first, Args&&... rest)
{
  stream << std::forward< T >( first );
  append_to_stream(stream, std::forward< Args >( rest ) ... );
}

http://ideone.com/cw6Mc

Error: User Rate Limit Exceededno matching call to std::forward()Error: User Rate Limit Exceeded Max
Error: User Rate Limit Exceeded...Error: User Rate Limit Exceededconst &Error: User Rate Limit ExceededforwardError: User Rate Limit Exceeded
15

std::endl это шаблон, а не функция, и компилятор не может решить, какиеendl использовать.

Пытаться:

append_to_stream(std::cout,
             std::endl<char, std::char_traits<char>>,
             std::endl<char, std::char_traits<char>>);

Или решение MooingDuck (исправлено):

template<class e, class t, class a> //string version
std::basic_ostream<e, t>& (*get_endl(const std::basic_string<e, t, a>&))
    (std::basic_ostream<e, t>& )
{ return std::endl<e,t>; } 

template<class e, class t> //stream version
std::basic_ostream<e, t>& (*get_endl(const std::basic_ostream<e, t>&))
    (std::basic_ostream<e, t>& )
{ return std::endl<e,t>; }

int main () {
  std::ostream& stream = std::cout;
  append_to_stream(stream,
                 get_endl(stream),
                 get_endl(stream));
}

Вот решение get_endl, упрощенное на C ++ 11decltype особенность:

template<class e, class t, class a> //string version
auto get_endl(const std::basic_string<e, t, a>&)
  -> decltype(&std::endl<e,t>)
{ return std::endl<e,t>; }

template<class e, class t> //stream version
auto get_endl(const std::basic_ostream<e,t>&)
  -> decltype(&std::endl<e,t>)
{ return std::endl<e,t>; }

int main () {
  std::ostream& stream = std::cout;
  append_to_stream(stream,
                 get_endl(stream),
                 get_endl(stream));
}
Error: User Rate Limit Exceededget_endlError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Max
Error: User Rate Limit ExceededautoError: User Rate Limit ExceededdecltypeError: User Rate Limit Exceeded
Error: User Rate Limit Exceededtemplate<class e, class t> basic_ostream<e,t>&(*)(basic_ostream<e,t>&os) get_endl(basic_ostream<e,t>& s) {return std::endl<e,t>;}Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Max

Похожие вопросы