2015-07-15 2 views
6

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

class SymbolGroup 
{ 
    std::string d_; 

public: 
    SymbolGroup(std::string a):d_(a){} 

    // explicit operator const std::string&() const { return d_;} // compiles 
    explicit operator std::string() const { return d_;} // Does not compile 
}; 

inline 
bool operator==(const SymbolGroup& lhs, const SymbolGroup& rhs) 
{ 
    return static_cast<const std::string&>(lhs) == 
    static_cast<const std::string&>(rhs); 
} 

int main(){ 

    SymbolGroup a("hello"); 
    SymbolGroup b("hello"); 

    if (a==b) 
    std::cout << "they are the same\n"; 

    return 0; 
} 

Без «сопзЬ» и «&» в определенной пользователем преобразования строки типа, она делает не компилируется в г ++ (4.8) с --std = C++ 11 флага:

error: invalid initialization of reference of type ‘std::string& {aka std::basic_string&}’ from expression of type ‘const string {aka const std::basic_string}’ explicit operator std::string&() const { return d_;}

код компилируется на Clang в обоих направлениях. Какой компилятор прав? Должен ли этот код компилироваться с operator std::string()?

+0

Я получаю [компиляционную ошибку] ​​(http://cpp.sh/6wbj) – CoryKramer

+1

@CoryKramer Вы скомпилировали версию без 'const' и '&'? – ENIGMA

+1

Just FYI - если вы задаете вопросы о компиляции кода, лучше написать пример как код, который не компилируется, чтобы люди могли просто скопировать и вставить. – Barry

ответ

4

UPDATE Мой предыдущий ответ был именно неправильно , Извиняюсь! tldr; clang является правильным, чтобы принять код, gcc неверно, чтобы отклонить его.


Во-первых, из [expr.static.cast]:

An expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e) ; is well-formed, for some invented temporary variable t (8.5).

Так эффективно мы пытаемся направить инициализировать объект типа std::string const& явно из объекта типа SymbolGroup const&. Существует раздел специально по инициализации ссылок с помощью функции преобразования: «Инициализация с помощью функции преобразования для прямой ссылки привязки» [over.match.ref]:

Under the conditions specified in 8.5.3, a reference can be bound directly to a glvalue or class prvalue that is the result of applying a conversion function to an initializer expression. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1 T” is the underlying type of the reference being initialized, and “cv S” is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:

— The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that [...] are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type “lvalue reference to cv2 T2” or “cv2 T2” or “rvalue reference to cv2 T2”, respectively, where T2 is the same type as T or can be converted to type T with a qualification conversion (4.4), are also candidate functions.

Первая часть не применяется, так как наша функция преобразования explicit, поэтому я пропустил его. Вторая часть. У нас есть cv1 T const std::string, поэтому наша функция преобразования в std::string является функцией-кандидатом, поскольку std::string может быть преобразована в const std::string с квалификационным преобразованием.


НКУ здесь не так, и я подал bug 66893, подтвержденная нашей собственной C++ эксперт и все вокруг хорошего парня Jonathan Wakely, а также головной Clang разработчик и C++ стандартный редактор Ричард Смит (после того, как я полностью смущен себя подачу ошибка Clang).

1

Ну, сэр, ответ я довольно прямолинейный. Вместо приведения к константной ссылке в ответ, как это:

return static_cast<const std::string&>(lhs) == static_cast<const std::string&>(rhs); 

Отдайте свой тип в std::string:

return static_cast<std::string>(lhs) == static_cast<std::string>(rhs); 

И наслаждайтесь рабочий код :)

+1

Это не отвечает на вопрос. Кроме того, OP хочет избежать копирования строк. – Barry

+1

Вещь '(const std :: string &) (lhs) == (const std :: string &) (rhs);' compiles и 'static_cast (lhs) == static_cast (rhs); 'does not. Разве это различие указано в стандарте? – dewaffled

+0

AFAIK с использованием c-style cast опасен в C++, потому что он заставляет компилятор выбирать способ литья самостоятельно.Таким образом, он может одновременно выполнять статические, const nad reinterpret cast. Возможно, в вашем примере он использует static и const cast together – bartop

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