Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > operator T ()


Автор: GoldFinch 1.10.2009, 17:40
какие проблемы могут возникнуть при использовании
  operator T () {return x;}
по сравнению с 
  T get() {return x;}
?

(когда-то слышал что этот оператор не всегда хорош, но забыл почему)

я хочу написать код
Код

class Foo
{
public:
    /*implicit*/ Foo(const std::string& value) : value_(value) {}
    Foo& operator=(const std::string& rhs) {value_.assign(rhs);}

    template<typename T>
    operator T () const { return boost::lexical_cast<T>(value); }

private:
    const std::string& value_;
};

Автор: zim22 1.10.2009, 17:47
Цитата(GoldFinch @  1.10.2009,  17:40 Найти цитируемый пост)
(когда-то слышал что этот оператор не всегда хорош, но забыл почему)

не хорош он неявным преобразованием типа.

Автор: GoldFinch 1.10.2009, 17:49
zim22, т.е.? мне вобщем-то это и надо, чтобы
работало
T x = foo; //Foo foo;

Автор: zim22 1.10.2009, 17:59
самый простой пример, иллюстрирующий проблему:
Код

class X {
public:
  X(int);
  operator int();
};
int operator+(X, X);

10 + X(1); // неоднозначность

***
вот, что в умной книжке пишут:
Цитата

Проблемы conversion operator:
* Они могут стать неисчерпаемым источником ошибок времени компиляции. Проблемы возникают тогда, когда существует несколько способов преобразования одного типа в другой.
* Когда в двух классах определены функции преобразования друг в друга, весьма вероятна неоднозначность.


Автор: GoldFinch 1.10.2009, 18:32
значит если нет функций, принимающих Foo, то все норм?

Автор: zim22 1.10.2009, 18:43
Цитата(GoldFinch @  1.10.2009,  18:32 Найти цитируемый пост)
значит если нет функций, принимающих Foo, то все норм?

всё будет норм, если не будет функций принимающих Foo, возвращающих Foo, использующих Foo, ... smile

Автор: GoldFinch 1.10.2009, 18:53
Цитата(zim22 @  1.10.2009,  19:43 Найти цитируемый пост)
всё будет норм, если не будет функций принимающих Foo, возвращающих Foo, использующих Foo, ... smile 

но при этом они должны быть еще и перегружены для T

ясно. у меня таких не планируется

Автор: xvr 2.10.2009, 10:16
Не должно быть пользовательских преобразований в обе стороны: т.е. если A можно неявно преобразовать в B, то не должно быть неявного преобразования B в A. 
В частности поэтому std::string нельзя преобразовать в char*, а надо явно звать c_str()

Автор: kemiisto 2.10.2009, 11:22
Цитата(zim22 @  1.10.2009,  18:59 Найти цитируемый пост)
самый простой пример, иллюстрирующий проблему:

Как мне кажется, тут проблема не в conversion operator, а в конструкторе, который надобно объявить как explicit. В Google C++ Style Guide есть про http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Explicit_Constructors.

А если ещё точнее, тут проблема в языке! smile 

Автор: bsa 2.10.2009, 11:50
kemiisto, не уверен, что std::string::string(const char *) нужно объявлять explicit.

Автор: kemiisto 2.10.2009, 12:16
bsa, там по ссылке есть ряд исключений:
Цитата

The exception is copy constructors, which, in the rare cases when we allow them, should probably not be explicit. Classes that are intended to be transparent wrappers around other classes are also exceptions. Such exceptions should be clearly marked with comments. 

std::string, в каком-то смысле, можно считать обёрткой для char*. smile 

Автор: GoldFinch 2.10.2009, 17:14
kemiisto, если мне надо неявное (implicit) преобразование - мне надо использовать неявное преобразование.

Добавлено через 3 минуты и 23 секунды
используя conversion operator я заметил что я могу написать
    T t = foo; // Foo { operator T() ... } foo;
но немогу написать
   1+foo
из за ошибки "не найден operator+(int,Foo)"

с этим можно что-то сделать?

Автор: zim22 2.10.2009, 17:41
Цитата(GoldFinch @  2.10.2009,  17:14 Найти цитируемый пост)
с этим можно что-то сделать?

определить  operator+(int,Foo)? smile

Автор: GoldFinch 2.10.2009, 17:43
zim22, лень.
их (операторов) слишком много, а юзать boost.preprocessor мне не хочется

Автор: zim22 2.10.2009, 17:52
Цитата(GoldFinch @  2.10.2009,  17:43 Найти цитируемый пост)
zim22, лень.

ну тогда
Код

template <typename T>
T operator+(T, Foo) {
  return T();
}

Foo f1("12");  
1 + f1;

 smile 
***
хотя это и не избавляет от необходимости определять для каждой операции шаблонную функцию...
***
мне в голову только ещё один вариант пришёл: обработка python|perl... 

Автор: GoldFinch 2.10.2009, 18:23
zim22, я ж говорю операторов много, каждый руками перегружать, для (T,Foo), (Foo,T), (Foo,Foo) - слишком долго, а с препроцессором тоже как-то не очень

Автор: mes 2.10.2009, 20:16
мне кажется что для данного совета по данному вопросу слишком много абстрактности..
имхо, подход сильно зависит от того, кем является foo по отношению к Т и что представляет из себя T ?

Автор: GoldFinch 2.10.2009, 20:45
mes, это выглядит так
Код

class Query
{
public:
    struct RVar
    {
        template<typename T>
        operator T () const
        {
            return boost::lexical_cast<T>(val);
        }

        RVar(const std::string& val_) : val(val_) {}

        const std::string& val;
    };

    RVar operator[] (const std::string& key) const;

    Query(const std::string& rhs) : query_(rhs) {}
private:
    const std::string& query_;
    mutable std::string value_;
};

Query::RVar Query::operator[]( const std::string& key ) const
{
    using namespace BOOST_SPIRIT_CLASSIC_NS;
    parse
        ( query_.c_str()
        , (str_p(key.c_str()) >> ch_p('=') >> (*(anychar_p-'&')) [assign_a(value_)] | *(anychar_p-'&')) % '&'
        );
    return RVar(value_);
}

...................................

создается объект 
    Query query("x=1&y=2");
и из него потом читаются значения
    int x = query["x"];
    int y = query["y"];

Автор: mes 2.10.2009, 21:59
Цитата(GoldFinch @  2.10.2009,  19:45 Найти цитируемый пост)
это выглядит так

а проблемa когда query[..] участвует в операциях ? 
там нужно явно указывать куда следует преобразовывать RVar.
Думаю лучше, чтоб не было неясностей, преобразование скрыть за шаблоной функцией, например
Код

template <typename T>  T as() const { return .. }
// тогда
 int x= query["x"].as<int>()+4;

Автор: GoldFinch 2.10.2009, 22:12
mes, так и сделал)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)