Автоматический шаблон ручной работы (без использования C++0x)

Как можно реализовать функциональность ключевого слова auto без использования стандарта С++ 0x?

for(std::deque<std::pair<int, int> >::iterator it = points.begin();
    it != points.end(); ++it)
{
   ...
}

Может такой класс:

class AUTO
{
public:
   template <typename T1>
   AUTO(T1);

   template <typename T2>
   operator T2();
};

При таком использовании:

for(AUTO it = points.begin(); it != points.end(); ++it)
{
   ...
}

Но Т1 и Т2 разные. Как перенести информацию о T1 в оператор T2()? Это действительно возможно?


person k06a    schedule 05.09.2010    source источник


Ответы (4)


Если бы расширение библиотеки было легко реализовать, то не было бы необходимости в расширении языка. Подробную информацию о авто предложение.

Однако статья на Boost.Foreach (какой тип делает то, что вы хотите) может помочь понять проблемы, связанные с таким реализация.

Что такое BOOST_FOREACH?

В C++ написание цикла, перебирающего последовательность, утомительно. Мы можем либо использовать итераторы, что требует значительного количества шаблонов, либо мы можем использовать алгоритм std::for_each() и переместить тело цикла в предикат, что требует не меньше шаблонов и заставляет нас перемещать наши логика далеко не там, где она будет использоваться. Напротив, некоторые другие языки, такие как Perl, предоставляют специальную конструкцию foreach, автоматизирующую этот процесс. BOOST_FOREACH — именно такая конструкция для C++. Он перебирает последовательности за нас, освобождая нас от необходимости иметь дело непосредственно с итераторами или писать предикаты.

BOOST_FOREACH разработан для простоты использования и эффективности. Он не выполняет динамического выделения памяти, не делает вызовов виртуальных функций или вызовов через указатели на функции, а также не делает вызовов, непрозрачных для оптимизатора компилятора. Это приводит к почти оптимальной генерации кода; производительность BOOST_FOREACH обычно находится в пределах нескольких процентов от эквивалентного цикла, закодированного вручную. И хотя BOOST_FOREACH — это макрос, он замечательно себя ведет. Он оценивает свои аргументы ровно один раз, что не приводит к неприятным сюрпризам.

person dirkgently    schedule 05.09.2010
comment
Я думаю о реализации только для использования в foreach. Ключевое слово auto в C++0x используется очень часто... Спасибо за ссылку, почитаю. - person k06a; 05.09.2010
comment
@ k06a: В C ++ существует сильное противодействие реализации чего-либо в качестве новой языковой функции, когда это можно реализовать в библиотеке. Поэтому, если что-то оказывается в самом языке, вы можете быть уверены, что никто не нашел способа правильно сделать это в библиотеке. (Например, то, что делают std::function и std::bind, встроено в язык многих других языков, но в C++ это библиотечная функция.) - person sbi; 06.09.2010
comment
Мне всегда было интересно, почему BOOST_FOREACH на несколько процентов отличается от закодированного вручную цикла. - person Viktor Sehr; 06.09.2010
comment
@sbi: и нельзя не отметить, что и std::function, и то, что производят std::bind, являются довольно неоптимальным представлением замыкания. На самом деле они пытались представить лучшую версию наряду с лямбдами C++0x — ранние предложения требовали, чтобы лямбда [&] была экземпляром определенного, хорошо известного магического типа функции, который компилятор затем мог бы эффективно реализовать как указатель на код + указатель на кадр стека (что не может быть сделано переносимым программистом). К сожалению, эта часть его была убита. - person Pavel Minaev; 11.09.2010

Существует макрос BOOST_AUTO, который более или менее делает то, что ключевое слово auto... Однако один взгляд на его реализацию скажет вам, что гораздо лучше найти способ использовать C++0x :>

person Kornel Kisielewicz    schedule 05.09.2010
comment
Кроме того, если компилятор не поддерживает decltype или typeof, BOOST_AUTO сможет обрабатывать только встроенные типы, а также многие стандартные библиотечные типы. Другие типы user.defined должны быть зарегистрированы, чтобы BOOST_AUTO распознал их, если я правильно помню. - person sellibitze; 07.09.2010

Вы можете использовать эти макросы, чтобы обойти это в соответствии со Стандартом.

#define DEF_DED(D, E) any_base const & D = make_any_concrete((E))
#define DED(D, E) get_t(D, true ? ded_ty() : get_idt((E)))

template<typename T> struct id {
  typedef T type;
};

template<typename T>
id<T> get_idt(T t) { return id<T>(); }

struct any_base { };

template<typename D>
struct any_concrete : any_base {
  any_concrete(D d):d(d) {}
  mutable D d;
};

template<typename T>
any_concrete<T> make_any_concrete(T x) { return any_concrete<T>(x); }

struct ded_ty {
  template<typename T>
  operator id<T>() { return id<T>(); }
};

template<typename T>
T &get_t(any_base const &b, id<T>) { return static_cast<any_concrete<T> const&>(b).d; }

Итак, ваш цикл for становится

for(DEF_DED(it, points.begin()); 
    DED(it, points.begin()) != points.end(); 
  ++DED(it, points.begin()))
{
   ...
}

Кредит принадлежит условной любви: FOREACH Redux Эрика Ниблера. Хотя не уверен, что оно того стоит :)

person Johannes Schaub - litb    schedule 10.09.2010

Более насущная проблема заключается в том, чтобы получить информацию из выведенного типа в объявление члена данных.

class AUTO
{
public:
   template <typename T1>
   AUTO(T1);

   T1 state; // eg deque<...>::iterator - need this!
};

Этого явно не произойдет, потому что объект AUTO должен быть выделен до вызова функции.

Однако, учитывая typeof или decltype, это не так сложно.

#define AUTO( name, initializer ) typeof( initializer ) name = initializer

Конечно, это имеет много ограничений. И typeof не является стандартным. С поддержкой нескольких компиляторов это, вероятно, станет основой для этих инструментов Boost.

person Potatoswatter    schedule 05.09.2010