Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 05:36
Оценка: -1
Здравствуйте!

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

#include "stdio.h"

namespace A {
    template <typename T>
    struct Key {
      T value;
    };

    template <typename Key>
    bool operator==(const Key &a, const Key &b) {
      return a.value == b.value;
    }
}
namespace B {
    template <typename KT, typename VT>
    struct MappedVal {
      VT value;
      A::Key<KT> key;
    };

    template <typename MappedVal>
    bool operator==(const MappedVal &a, const MappedVal &b) {
      return (a.key == b.key && a.value == b.value);
    }
}

int main() {
  A::Key<short> key1, key2;
  key1.value = 1;
  key2.value = 1;

  B::MappedVal<short, double> val1, val2;
  val1.key = key1;
  val1.value = 12.41;

  val2.key = key1;
  val2.value = 12.41;

  bool test1 = (key1 == key2);
  bool test2 = (val1 == val2);

  printf("key1 == key2: %s", (test1 ? "true" : "false"));
  printf("val1 == val2: %s", (test2 ? "true" : "false"));

  return 0;
}


если сделать операторы функциями-членами, то все компилируется:

#include "stdio.h"
#include <vector>

namespace A {
    template <typename T>
    struct Key {
      T value;
      
        template <typename Key>
        bool operator==(const Key &b) {
          return this->value == b.value;
        }
    };
}
namespace B {
    template <typename KT, typename VT>
    struct MappedVal {
      VT value;
      A::Key<KT> key;

        template <typename MappedVal>
        bool operator==(const MappedVal &b) {
          return (this->key == b.key && this->value == b.value);
        }
    };
}

int main() {
  A::Key<short> key1, key2;
  key1.value = 1;
  key2.value = 1;

  B::MappedVal<short, double> val1, val2;
  val1.key = key1;
  val1.value = 12.41;

  val2.key = key1;
  val2.value = 12.41;

  bool test1 = (key1 == key2);
  bool test2 = (val1 == val2);
  
  if (test1 && test2)
  {
    printf("OK\n");
  }else
  {
    printf("failure\n");      
  }

  return 0;
}


Стоит задача сделать код компилируемым без использования операторов-членов классов.
Какие будут идеи?
Третий Рим должен пасть!
Re: Операторы-функции vs операторы-члены
От: night beast СССР  
Дата: 20.02.14 05:40
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Здравствуйте!


GC>Есть код который не собирается (кусок кода без смысла, показывающий суть):


GC>namespace A {
GC>    template <typename T>
GC>    struct Key {
GC>      T value;

GC>      friend bool operator==(const Key &a, const Key &b) {
GC>         return a.value == b.value;
GC>      }

GC>    };

GC>}
GC>namespace B {
GC>    template <typename KT, typename VT>
GC>    struct MappedVal {
GC>      VT value;
GC>      A::Key<KT> key;
GC>    };

GC>    template <typename KT, typename VT>
GC>    bool operator==(const MappedVal<KT,VT> &a, const MappedVal<KT,VT> &b) {
GC>      return (a.key == b.key && a.value == b.value);
GC>    }
GC>}


GC>Стоит задача сделать код компилируемым без использования операторов-членов классов.

GC>Какие будут идеи?
Re: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 05:54
Оценка:
Нашли вот такое решение с использованием шаблонных шаблонных параметров:

#include "stdio.h"

namespace A {
    template <typename T>
    struct Key {
      T value;
    };

    template <
        typename T,
        template<typename> class KeyType
    >
    bool operator==(const KeyType<T> &a, const KeyType<T> &b) {
      return a.value == b.value;
    }
}
namespace B {
    template <typename KT, typename VT>
    struct MappedVal {
      VT value;
      KT key;
    };

    template <
        typename KT,
        typename VT,
        template<typename,typename> class MappedType
    >
    bool operator==(const MappedType<KT, VT> &a, const MappedType<KT, VT> &b) {
      return (a.key == b.key && a.value == b.value);
    }
}

int main() {
  A::Key<short> key1, key2;
  key1.value = 1;
  key2.value = 1;

  B::MappedVal<A::Key<short>, double> val1, val2;
  val1.key = key1;
  val1.value = 12.41;

  val2.key = key1;
  val2.value = 12.41;

  bool test1 = (key1 == key2);
  bool test2 = (val1 == val2);

  printf("key1 == key2: %s\n", (test1 ? "true" : "false"));
  printf("val1 == val2: %s\n", (test2 ? "true" : "false"));

  return 0;
}
Третий Рим должен пасть!
Re[2]: Операторы-функции vs операторы-члены
От: lxa http://aliakseis.livejournal.com
Дата: 20.02.14 08:08
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Нашли вот такое решение с использованием шаблонных шаблонных параметров:


Так, например, не работает.
Может, так?
Re: Операторы-функции vs операторы-члены
От: Кодт Россия  
Дата: 20.02.14 08:21
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Есть код который не собирается (кусок кода без смысла, показывающий суть):


Потому что синтаксис же!
Оператор, объявленный внутри класса, должен быть или членом (подразумевая this левым аргументом), или другом.

GC>Стоит задача сделать код компилируемым без использования операторов-членов классов.


Откуда такая задача встала?
Перекуём баги на фичи!
Re: Операторы-функции vs операторы-члены
От: Chorkov Россия  
Дата: 20.02.14 09:54
Оценка:
Здравствуйте, GhostCoders, Вы писали:

GC>Здравствуйте!


GC>Есть код который не собирается (кусок кода без смысла, показывающий суть):

...
GC>Стоит задача сделать код компилируемым без использования операторов-членов классов.
GC>Какие будут идеи?



#include "stdio.h"

namespace A {
    template <typename T>
    struct Key {
      T value;
    };

    template <typename T>
    bool operator==(const Key<T> &a, const Key<T> &b) {
      return a.value == b.value;
    }
}
namespace B {
    template <typename KT, typename VT>
    struct MappedVal {
      VT value;
      A::Key<KT> key;
    };
    

    // Ограничиваем оператор только нужным нам шаблонным типом.
    // Ранее он был применим ко всем типам подряд.
    template <typename KT, typename VT>
    bool operator==(const MappedVal<KT,VT> &a, const MappedVal<KT,VT> &b) {
      return (a.key == b.key && a.value == b.value);
    }
}

int main() {
  A::Key<short> key1, key2;
  key1.value = 1;
  key2.value = 1;

  B::MappedVal<short, double> val1, val2;
  val1.key = key1;
  val1.value = 12.41;

  val2.key = key1;
  val2.value = 12.41;

  bool test1 = (key1 == key2);
  bool test2 = (val1 == val2);

  printf("key1 == key2: %s", (test1 ? "true" : "false"));
  printf("val1 == val2: %s", (test2 ? "true" : "false"));

  return 0;
}
Re: Операторы-функции vs операторы-члены
От: andrew.f  
Дата: 20.02.14 10:13
Оценка: -1
Здравствуйте, GhostCoders, Вы писали:

Эта штука называется — Koenig Name Lookup.
Поиск по гуглу много чего дает, например, Саттер: http://www.gotw.ca/gotw/030.htm.

Смысл в том, что у тебя оператор определен внутри namespace, using этого namespace отсутствует, в результате — компилятор не резолвит определенный тобой оператор.
Выход — явно указать в качестве параметра A::Key — тогда сработает Koenig Name Lookup.

Это свойство активно используется внутри STL — те же операторы в потоках ввода-вывода...

GC>Здравствуйте!


GC>Есть код который не собирается (кусок кода без смысла, показывающий суть):

...

GC>Стоит задача сделать код компилируемым без использования операторов-членов классов.

GC>Какие будут идеи?
Re[2]: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 10:36
Оценка:
не так. Как раз Koenig Name Lookup позволяет работать без использования using namespace,
например, по ссылке что вы давали там есть такой код:

    namespace NS {
        class T { };
        void f(T);
    }

    NS::T parm;
    int main() {
        f(parm);    // OK, calls NS::f
    }

метод f() вызывается из пространства NS без использования using namespace.


Здравствуйте, andrew.f, Вы писали:

AF>Здравствуйте, GhostCoders, Вы писали:


AF>Эта штука называется — Koenig Name Lookup.

AF>Поиск по гуглу много чего дает, например, Саттер: http://www.gotw.ca/gotw/030.htm.

AF>Смысл в том, что у тебя оператор определен внутри namespace, using этого namespace отсутствует, в результате — компилятор не резолвит определенный тобой оператор.

AF>Выход — явно указать в качестве параметра A::Key — тогда сработает Koenig Name Lookup.

AF>Это свойство активно используется внутри STL — те же операторы в потоках ввода-вывода...


GC>>Здравствуйте!


GC>>Есть код который не собирается (кусок кода без смысла, показывающий суть):

AF>...

GC>>Стоит задача сделать код компилируемым без использования операторов-членов классов.

GC>>Какие будут идеи?
Третий Рим должен пасть!
Re[2]: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 10:40
Оценка:
Да, вы все правильно предлагаете.
У нас было так в одном из первоначальных вариантов.

Но тут смысл сделать так чтобы алгоритмы (всякие операторы работы над структурами данных)
работали с разными реализациями этих структур данных.

В данном подходе типы данных вшиты жестко — это Key<T> и MappedVal<KT,VT>.
А хотелось бы чтобы они работали с любыми шаблоными типа KeyType<T> и MappedType<KT,VT>.

См. решение в моем соседнем посте.


Здравствуйте, Chorkov, Вы писали:

C>Здравствуйте, GhostCoders, Вы писали:


GC>>Здравствуйте!


GC>>Есть код который не собирается (кусок кода без смысла, показывающий суть):

C>...
GC>>Стоит задача сделать код компилируемым без использования операторов-членов классов.
GC>>Какие будут идеи?



C>
C>#include "stdio.h"

C>namespace A {
C>    template <typename T>
C>    struct Key {
C>      T value;
C>    };

C>    template <typename T>
C>    bool operator==(const Key<T> &a, const Key<T> &b) {
C>      return a.value == b.value;
C>    }
C>}
C>namespace B {
C>    template <typename KT, typename VT>
C>    struct MappedVal {
C>      VT value;
C>      A::Key<KT> key;
C>    };
    

C>    // Ограничиваем оператор только нужным нам шаблонным типом.
C>    // Ранее он был применим ко всем типам подряд.
C>    template <typename KT, typename VT>
C>    bool operator==(const MappedVal<KT,VT> &a, const MappedVal<KT,VT> &b) {
C>      return (a.key == b.key && a.value == b.value);
C>    }
C>}

C>int main() {
C>  A::Key<short> key1, key2;
C>  key1.value = 1;
C>  key2.value = 1;

C>  B::MappedVal<short, double> val1, val2;
C>  val1.key = key1;
C>  val1.value = 12.41;

C>  val2.key = key1;
C>  val2.value = 12.41;

C>  bool test1 = (key1 == key2);
C>  bool test2 = (val1 == val2);

C>  printf("key1 == key2: %s", (test1 ? "true" : "false"));
C>  printf("val1 == val2: %s", (test2 ? "true" : "false"));

C>  return 0;
C>}
C>
Третий Рим должен пасть!
Re[2]: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 10:45
Оценка:
Смысл сделать так чтобы алгоритмы (всякие операторы работы над структурами данных)
работали с разными реализациями этих структур данных.

Если делать их членами классов, то для каждого нового класса нужно их реализовывать.
Но полиморфизм использовать не хочется, нужно compile time полиморфизм.

Тут другом делать их не обязательно так как эти структуры — это обычные структуры (с открытыми полями).

Подразумевается что каждая реализация таких структур будут предоставлять минимальный функционал (operator[], и некоторые другие).



Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, GhostCoders, Вы писали:


GC>>Есть код который не собирается (кусок кода без смысла, показывающий суть):


К>Потому что синтаксис же!

К>Оператор, объявленный внутри класса, должен быть или членом (подразумевая this левым аргументом), или другом.

GC>>Стоит задача сделать код компилируемым без использования операторов-членов классов.


К>Откуда такая задача встала?
Третий Рим должен пасть!
Re[3]: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 10:48
Оценка:
Здравствуйте, lxa, Вы писали:

lxa>Так, например, не работает.

странно, у нас собирается.

lxa>Может, так?

к сожалению не подходит, смысл в разделении алгоритмом от обрабатываемых структур данных.
То есть алгоритмы должны быть весьма независимы от структур данных над которыми они работают.
Третий Рим должен пасть!
Re[2]: Операторы-функции vs операторы-члены
От: Кодт Россия  
Дата: 20.02.14 10:52
Оценка:
К>Оператор, объявленный внутри класса, должен быть или членом (подразумевая this левым аргументом), или другом.

Совсем плоха глазами стала. Читал namespace как class
Перекуём баги на фичи!
Re[4]: Операторы-функции vs операторы-члены
От: GhostCoders Россия  
Дата: 20.02.14 11:00
Оценка:
GC>Здравствуйте, lxa, Вы писали:

lxa>>Так, например, не работает.

GC>странно, у нас собирается.
вот варинат который работает http://ideone.com/rzOm5r
Третий Рим должен пасть!
Re[3]: Операторы-функции vs операторы-члены
От: Chorkov Россия  
Дата: 20.02.14 11:32
Оценка: 4 (1)
Здравствуйте, GhostCoders, Вы писали:

GC>Да, вы все правильно предлагаете.

GC>У нас было так в одном из первоначальных вариантов.

GC>Но тут смысл сделать так чтобы алгоритмы (всякие операторы работы над структурами данных)

GC>работали с разными реализациями этих структур данных.

GC>В данном подходе типы данных вшиты жестко — это Key<T> и MappedVal<KT,VT>.

GC>А хотелось бы чтобы они работали с любыми шаблоными типа KeyType<T> и MappedType<KT,VT>.

GC>См. решение в моем соседнем посте.


По сути, у тебя две группы шаблонов: KeyType-like и MappedType-like.
Для них переменяются разные операторы сравнения.
Если определять к какой группе относиться тип, можно по числу аргументов шаблона, то у тебя уже есть решение.
Если на число аргументов тоже нельзя опираться — можно пометить нужные типы вручную.
(+ ebnable_if для оператора сравнения.)
Re[3]: Операторы-функции vs операторы-члены
От: andrew.f  
Дата: 20.02.14 11:47
Оценка: -1
Здравствуйте, GhostCoders, Вы писали:

GC>не так. Как раз Koenig Name Lookup позволяет работать без использования using namespace,


Я про это и написал, что using namespace у тебя отсутствует и оператор не резолвится:
AF >Смысл в том, что у тебя оператор определен внутри namespace, using этого namespace отсутствует, в результате — компилятор не резолвит определенный тобой оператор.

И ниже рецепт решения:
AF>>Выход — явно указать в качестве параметра A::Key — тогда сработает Koenig Name Lookup.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.