2013-07-14 4 views
21

Есть ли способ написать функцию в C++, которая принимает как аргументы lvalue, так и rvalue, не делая ее шаблоном?Функция, которая принимает как аргументы lvalue, так и rvalue

Например, предположим, что я пишу функцию print_stream, которая читает с istream и печатает данные, которые были прочитаны на экране, или что-то в этом роде.

Я думаю, что это разумно назвать print_stream так:

fstream file{"filename"}; 
print_stream(file); 

, а также, как это:

print_stream(fstream{"filename"}); 

Но как же я заявляю print_stream так, что оба использует работу?

Если я объявить его как

void print_stream(istream& is); 

то второе использование не будет компилировать, потому что Rvalue не будет связываться с неконстантной ссылкой-значения.

Если я объявить его как

void print_stream(istream&& is); 

то первое использование не будет компилировать, потому что именующий не будет связываться с ссылкой RValue.

Если я объявляю его как

void print_stream(const istream& is); 

тогда реализация функция не будет компилироваться, так как вы не можете прочитать из const istream.

Я не могу сделать функцию шаблоном и использовать «универсальную ссылку», потому что ее реализация должна быть отдельно скомпилирована.

Я мог бы привести две перегрузки:

void print_stream(istream& is); 
void print_stream(istream&& is); 

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

Есть ли что-то лучшее, что я могу сделать?

+0

У вас может быть void print_stream (Wrapper) и переместить проблему в конструктор Wrapper, что имеет смысл, если вы хотите сделать то же самое для нескольких функций. –

+2

"каждый раз, когда я пишу функцию с семантикой, подобной этой?" Часто ли вы записываете функции, которые должны принимать неконстантный аргумент без копирования, и должны быть вызваны как с временным, так и с параметром lvalue? Это довольно конкретный случай, и я не буду беспокоиться о том, «каждый раз, когда мне приходится писать функцию с семантикой, подобной этой». Если параметр был скопирован, вы можете просто передать его по значению. Если вам не нужно было называть неконстантные функции на нем, вы могли бы пройти по ссылке const – jalf

+2

Вы могли бы написать шаблон помощника-лидера T & stay (T && t) {return t; } 'и используйте' stay (fstream {"filename"}) '. –

ответ

15

Существует не так много из sane выбор, кроме предложения двух перегрузок или создания вашей функции шаблона, я бы сказал.

Если вы действительно, действительно нужен (безобразно) альтернативу, то я думаю, единственный (безумный), что вы можете сделать, это есть ваша функция принимать const&, с условием о том, что вы не можете передать объект const -qualified типа к нему (вы все равно не хотите его поддерживать). Затем функции будет разрешено отбрасывать значение const.

Но я бы лично написать две перегруженные и определить один в терминах других, так что вы продублировать заявление, но не определение:

void foo(X& x) 
{ 
    // Here goes the stuff... 
} 

void foo(X&& x) { foo(x); } 
+1

это недостаточно масштабируется (например, 3 параметра -> 8 функций). Есть ли способ обойти это? Я нахожусь в том же положении, что и ОП. – Dave

+1

@Dave Что-то вроде этой работы для вашего случая использования? http://coliru.stacked-crooked.com/a/e93ea8c3b693b593 – Mysticial

+0

@ Мистицизм - это довольно аккуратное обходное решение, но, к сожалению, через 3 года я полностью забыл, зачем мне это нужно. Я буду помнить об этом, если это когда-нибудь снова появится! – Dave

4

Другой довольно уродливой альтернативой сделать функцию а шаблон и явно создавать экземпляры обеих версий:

template<typename T> 
void print(T&&) { /* ... */ } 

template void print<istream&>(istream&); 
template void print<istream&&>(istream&&); 

Это может быть скомпилировано отдельно. Клиентскому коду требуется только объявление шаблона.

Я бы лично придерживался того, что предлагает Энди Проул.

+0

@ HighCommander4 [работает для меня.] (Http://coliru.stacked-crooked.com/view?id=fa0857865f55a2615158e93e8ceb5a76-3725be9f9ce62f113fc473b4ae69c419) – jrok

Смежные вопросы