Стирание типа для методов с разными типами возврата - PullRequest
4 голосов
/ 22 мая 2011

Мне было интересно, существует ли какая-либо форма стирания типа для работы с методами, которые имеют одинаковые имена и аргументы, но возвращают разные значения, как в моем примере ниже (begin и end).Я не планирую использовать это где-либо, мне просто интересно узнать, возможно ли это, и, если да, то как это будет сделано.

Единственная известная мне форма стирания типов - это указатель на чисто виртуальный класс concept, который указывает на model<T>, который перенаправляет вызовы в базовый T.Однако для этого требуется, чтобы все T содержали методы с одинаковой сигнатурой, тогда как в моем примере возвращаемые типы различаются.Насколько я могу сказать, что-то похожее на функции виртуального шаблона потребуется для выполнения того, что я прошу, но я могу что-то упустить.

class Iterable
{
    //how would this be defined?
}

int main(int argc, char *argv[])
{
    vector<int> v = {1, 2, 3, 4, 5};
    set<string> s = {"foo", "bar", "baz"};

    Iterable iterable;

    if(argc == 2) iterable = v;
    else iterable = s;


    for(auto val : it)
    { 
        cout << val << ' ';
    }
}

Ответы [ 4 ]

10 голосов
/ 22 мая 2011

Стирание типа может и было реализовано в C ++ в разных контекстах.Наиболее распространенный подход, который используется в boost::any, std::function< signature >, std::thread и других, основан на неполиморфном классе, который является стертым типом *1005* объекта, который содержит указатель на интерфейстип.Внутри, во время построения, назначения или всякий раз, когда пользовательский тип стирается, реализация интерфейса сохраняется и сохраняется.

В качестве упрощенного примера мотивации, рассмотрим, что мы хотели создать printable тип, который может бытьиспользуется для печати любого типа, который реализует operator<< до std::cout, используя стирание типа.Для этого нам понадобится тип printable, внутренний интерфейс printable_impl_base и фактические реализации:

// regular polymorphic hierarchy:
struct printable_impl_base {
   virtual ~printable_impl_base() {}
   virtual void print() const = 0;
};
template <typename T>
struct printable_impl : printable_impl_base {
   T copy_to_print;
   printable_impl( T const & o ) : copy_to_print( o ) {}
   virtual void print() const {
      std::cout << copy_to_print << std::endl;
   }
};

// type erasure is performed in printable:
class printable {
   std::shared_ptr<printablable_impl_base> p;
public:
   template <typename T>
   printable( T obj ) : p( new printable_impl<T>(obj) ) {}
   void print() const {
      p->print();
   }
};

Обратите внимание, что шаблон очень похож на обычную полиморфную иерархию с той разницей, что интерфейс добавлен объект, представляющий собой тип значения (заимствующий термин тип значения из C #), который содержит фактические полиморфные объекты внутри.

Глядя на это таким образом,это кажется несколько упрощенным и бесполезным, но это топливо, которое управляет boost::any (внутренний интерфейс - это только typeid), std::function< void () > (внутренний интерфейс реализует void operator()) или shared_ptr<> (интерфейс - это метод удаления, который освобождает ресурс).

Существует один конкретный другой тип стирания типа, когда единственное, что нужно сделать с типом, реализующим стирание типа, - это уничтожить его: использоватьвременно и связать его с постоянной ссылкой ... Но это очень специфично, если вы хотите, вы можете прочитать об этом здесь: http://drdobbs.com/cpp/184403758

ВВ конкретном случае, о котором вы говорите в этом вопросе, он немного сложнее, потому что вы не хотите удалять один тип, а скорее пару из них.Интерфейс Iterable должен удалять тип контейнера, который он содержит внутри, и при этом он должен предоставлять свои собственные итераторы, которые должны выполнять стирание типа на итераторах из контейнера.Тем не менее, идея в основном та же самая, просто больше работы, чтобы сделать.

1 голос
/ 22 мая 2011

Вас может заинтересовать boost::any:

http://www.boost.org/doc/libs/1_46_1/doc/html/any.html

0 голосов
/ 23 мая 2011

Стандартная библиотека C ++ не поддерживает дисперсию времени выполнения в своих типах контейнеров.Нет ничего плохого в реализации этого, однако, управление памятью без сборки мусора на уровне языка будет непростым, и вы будете получать удовольствие, делая его производительным.

Стоит упомянуть, что в некоторых реализациях STL они реализуют нечто, известное как итерация SCARY, где vector<int, std::allocator<int>>::iterator соответствует типу vector<int, mycustomallocator<int>>::iterator.

Кроме того, вам необходимоочень осторожно.Вектор определенно является RandomAccessIterable, но набор является только ConstIterable и определенно не является RandomAccessIterable, а InputIterator является только ForwardIterable.Вам необходимо определить шаблоны для всех этих сценариев.

0 голосов
/ 22 мая 2011

Всякий раз, когда я вижу термин "стирание типа", я чувствую себя некомфортно.Почему в строго типизированном (или слабо типизированном) языке вы хотите стереть тип?

И нет, вы не можете этого сделать.

...