Я пытаюсь преобразовать класс A
в строку как таковую:
#include <iostream>
#include <string>
class A {
public:
std::string data_ = "hello world";
A() {}
operator std::string() const {
return data_;
}
template <typename T>
operator T() const {
return data_;
}
};
int main() {
A();
// This fails
// std::string s;
// s = A();
std::string s = A(); // This works
return 0;
}
Я пытаюсь решить ту часть, где s = A();
. Он терпит неудачу во время компиляции, и компилятор сообщает мне, что нет оператора присваивания '=', который присваивает A
строке.
Что интересно:
std::string s = A();
), включается «оператор преобразования», и он работает (но я хочу, чтобы s = A()
также работал).s = A();
будет работать.Может кто-нибудь объяснить, что вызывает различное поведение?
У меня работает, когда удаляю шаблон. wandbox.org/permlink/ThiX9mLrvGsb1XlT. М.М прав в том, что ваша программа неоднозначна.
@ M.M примерил clang и gcc. Да, я понимаю, что это неоднозначно, но я действительно не знаю, когда оператор преобразования имеет приоритет над оператором присваивания.
@ smac89 Я уже упоминал во втором пункте, он работает, если вы удалите метод шаблона. Любопытно, почему поведение отличается, когда его вводят.
напишите свой шаблон как operator typename std::remove_all_extents<T>::type() const {
- он скомпилируется
@chutsu проблема в том, что существует множество перегрузок std::string::operator=
и множество возможных пользовательских последовательностей преобразования; Например, string::operator=(string)
<- A::operator string
не предпочтительнее, чем std::operator=(char *)
<- A::operator char *
. Этого не возникает в других примерах, поскольку они не связаны с operator=
.
Решение простое. Сделайте это явным, а не неявным преобразованием:
template <typename T>
explicit operator T() const {
return data_;
}
Преимущество в том, что теперь работают все четыре возможности:
std::string s;
s = A();
std::string s2 = A(); // This works
std::string s3 = std::string(A());
std::string s4;
s4 = std::string(A());
Можете ли вы объяснить, почему явное указание оператора решает проблему? Имеет ли этот новый оператор приоритет над существующей версией без шаблона?
Этот результат эквивалентен полному удалению operator T()
, потому что operator std::string
уже присутствует в примере. Спрашивающий уже заметил: «Если я удалю шаблонный метод, s = A (); работает». Предположительно, задающий вопрос хочет решение, которое преобразует типы Другие, а не std::string()
?
@Lack - это не эквивалент полного удаления operator T()
. Если у вас есть T
, который может быть сконструирован из string
, его все равно можно явно вызвать
@ user463035818 Результат эквивалентен в этом примере. Все "четыре возможности", которые вы показываете, называются operator std::string
; никто не вызывает explicit operator T
. Если у вас есть пример, в котором оператор explicit
делает что-то полезное, ваш ответ будет улучшен, если он будет показан.
@ Отсутствие, это не мой ответ;). Во всяком случае, насколько я понимаю OP, они действительно хотят, чтобы вызвал operator std::string
, и причина, по которой он не работал, заключалась в существовании operator T
, что делает operator T
явным, позволяет вам вызывать operator string
неявно без двусмысленности
Ой, перепутал числовые имена пользователей! Конечно. Я предполагаю, что OP не совсем ясно, как они на самом деле используют operator T
.
Какой компилятор вы используете? gcc и clang объясняют, что происходит (неоднозначная перегрузка)