2016-10-07 3 views
7

Я пытаюсь написать класс со своими собственными операторами литых, но у меня возникли проблемы с кратному operator= ами«оператор =» неоднозначен для станд :: строка

мне удалось воспроизвести проблему с небольшим кодом ниже

#include <string> 

class X 
{ 
public: 
    operator const char*() const { 
    return "a"; 
    } 
    operator std::string() { 
    return "c"; 
    } 
}; 

void func() 
{ 
    X x; 
    std::string s = ""; 
    s = x; 
} 

Я понимаю, что std::basic_string имеет несколько оператор присваивания и поэтому компилятор запутается.

Если я удаляю любые операторы приведения, это работает, но мне было интересно, есть ли способ удерживать обоих операторов.

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

Я мог бы также использовать static_cast<std::string>(x), чтобы заставить актерский состав, но мне было интересно, есть ли способ сделать это без статического литья?

+0

Как насчет 's = std :: string (x)'? –

+0

Да, актер будет работать (как упоминалось в моем сообщении), но мой вопрос больше, если я мог бы намекнуть компилятору, что использовать, чтобы мне не нужно было использовать листинг. –

+2

Разве это не отличная «подсказка для компилятора»? –

ответ

2

Как KerrekSB suggested, вы можете использовать

s = std::string(x); 

В качестве альтернативы, вы можете выполнить бросок:

s = (std::string) x; 
// or 
s = static_cast<std::string>(x); 

Третий вариант (который я хотел бы надеяться, чтобы не видеть в дикой природе очень часто из-за для удобства чтения) заключается в непосредственном доступе к оператору:

s = x.operator std::string(); 

Если вы готовы сделать компромисс в несколько иного API (и устранив возможные обрывы), вы можете делать то, что Роберто suggested и заставить явную отливку толькоconst char * типа оператор:

class X 
{ 
public: 
    explicit operator const char*() const { 
    return "a"; 
    } 
    operator std::string() { 
    return "c"; 
    } 
}; 

Это говорит компилятору разрешить только неявным конверсиям в std::string и требует, чтобы вы явно приводили к const char *, когда вы хотите вызвать этого конкретного оператора.


последнее, что следует отметить: если вы разрабатываете другие классы или методы, которые потребляют этот конкретный класс, другое дело, чтобы попытаться это полностью изменить способ, которым они используются, обеспечивая перегрузку для class X, а не преобразовывать X что-то еще.

Всегда полезно рассмотреть альтернативные способы работы вашего API.

+1

Формально 'std :: string (x)' также является * cast * (написано в функциональной нотации). – AnT

+0

@AnT 'std :: string (x)' вызывает конструктор и не выполняет фактический отбор - компилятор может оптимизировать это вниз, конечно, но семантически это не то, что происходит. – Qix

+0

Итак? '(std :: string) x' также вызывает конструктор. И да, 'std :: string (x)' - это литье, точно так же, как оно определено в стандарте языка. A * cast * - чисто синтаксический элемент языка. Семантика броска сводится к семантике преобразования типов. Последнее зависит от используемых типов. Язык на самом деле явно говорит о том, что функциональная нотация с единственным аргументом эквивалентна классическому литовому нотации с тем же аргументом. То есть 'std :: string (x)' cast определяется как эквивалент '(std :: string) x' cast. – AnT

2

Если вы используете ключевое слово explicit на char * cast, вы будете использовать листинг по умолчанию для std :: string.

class X 
{ 
public: 
    explicit operator const char*() const { 
     return "a"; 
    } 
    operator std::string() { 
     return "c"; 
    } 
}; 

после него ваши забросы:

X x; 
std::string s = ""; 
s = x; 

будет преуспевают (и пользователь вашего класса нужно будет указать символ * литая, если он хочет использовать другой оттенок)

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

+0

Это также отличная альтернатива, хотя она немного изменяет семантику вашего API и может привести к поломке кода (хотя это может быть хорошим компромиссом). Не думал об этом. – Qix

+3

Вы правы @Qix, я предпочитаю, чтобы оба приведения были явными, но я думаю, что Саймон должен решить, что – Roberto

+0

'const char * c = x;' больше не будет работать таким образом. Вы просто нарушаете api наоборот. – skypjack

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