2015-01-28 7 views
7

Этот образец кода действителен?Возвращает стандартную стандартную ссылку?

using ref = char&; 

ref foo(ref x) { 
    return ref{x}; 
} 

int main() { 
    char a; 
    foo(a); 
    return 0; 
} 

кажется, что:

  • лязг 3,5 говорит ДА
  • НКУ 4,9 говорит не

    main.cpp: In function 'char& foo(ref)': 
    main.cpp:4:15: error: invalid cast of an rvalue expression of type 'char' to type 'ref {aka char&}' 
        return ref{x}; 
          ^
    

http://coliru.stacked-crooked.com/a/cb6604b81083393f

Какой компилятор прав? или это неуказано?

Это очень легко, поэтому преодолеть Gcc ошибку сборки по:

  1. используя круглые скобки вместо фигурных скобок

    ref foo(ref x) { 
        return ref(x); 
    } 
    
  2. называя возвращенное значение

    ref foo(ref x) { 
        ref ret{x}; 
        return ret; 
    } 
    

вариант 1. прерывает равномерную инициализацию, вариант 2. добавляет бесполезную строку кода.

Похожий вопрос уже был aked здесь: Why can't I initialize a reference in an initializer list with uniform initialization?

Но упомянутый pr50025 фиксируется в GCC 4.9.

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

#include <utility> 
template <typename Tp, typename... Us> 
Tp bar(Us&&... us) { 
    return Tp{std::forward<Us>(us)...}; 
} 

ответ

3

Это похоже упущением в стандарте, где GCC реализует именно то, что стандарт требует, и лязг собирается за то, что, вероятно, задумано.

От C++ 11 (курсив мой):

5.2.3 Явное преобразование типов (функциональное обозначение) [expr.type.conv]

1 A простой-типа- спецификатор (7.1.6.2) или typename-specifier (14.6), за которым следует скобковый список , строит значение указанного типа, учитывая список выражений. Если список выражений является одним выражением, выражение преобразования типа эквивалентно (в определенности и, если определено по смыслу), в соответствующее выражение (5.4). [...]

[...]

3 Аналогично, простой типа спецификатор или Ьурепате-спецификатор с последующим рамно-инициализации-лист создает временный объект указанного типа прямого списка инициализируется (8.5.4) с указанным braced-init-list, и его значением является то, что временный объект как prvalue.

Для приготовился-INIT-лист случае, стандарт не определяет, что, что это работает точно так же, как C-стиль актеры. И это не делает:

typedef char *cp; 
int main() { 
    int i; 
    (cp(&i)); // okay: C-style casts can be used as reinterpret_cast 
    (cp{&i}); // error: no implicit conversion from int * to char * 
} 

К сожалению, T(expr) быть эквивалентно (T)expr также одно исключение, в котором функциональный литой не обязательно производят prvalue. В стандарте не указывается аналогичное исключение для функционального литья, используя бит-init-list для ссылочного типа. В результате в вашем примере ref{x} создает временный тип ref, с прямым списком-инициализацией от {x}. Затем это временное отношение рассматривается как prvalue, потому что это то, что стандарт говорит, что поведение должно быть, и что prvalue не может использоваться для привязки к ссылке lvalue.

Я очень подозреваю, что если бы это было доведено до комитета ISO C++, стандарт был бы изменен, чтобы требовать поведения clang, но на основе текущей формулировки стандарта, я думаю, что это GCC, это правильно, по крайней мере для вашего конкретный пример.

Вместо добавления переменной, или переключение на круглые скобки можно опустить ref (Tp), чтобы избежать этой проблемы:

template <typename Tp, typename... Us> 
Tp bar(Us&&... us) { 
    return {std::forward<Us>(us)...}; 
} 
+0

Опуская 'Tp' в выбросе оператор возврата' 'Tp's с explicit' конструкторах ... Общая функция уже не так обобщена –

+0

@KarolWozniak Это хороший момент. С другой стороны, то, что у вас уже есть (все три версии), требует доступного экземпляра копирования или перемещения, поэтому он уже не является таким общим, каким он мог бы быть. У меня нет хорошей альтернативы, которая охватывает все возможные типы, извините. – hvd

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