2010-01-01 3 views
3

Я использую ЬурейиЙ определить тип контейнера в моей программе, так что я могу легко переключаться между использованием обычных контейнеров STL и STXXL контейнеров, вдоль линий:Перегрузки for_each для конкретных типов итераторов

typedef stxxl:vector<Data> MyContainer; 

или

typedef std:vector<Data> MyContainer; 

Одна трудность заключается в том, что STXXL предоставляет специальную версию std::for_each, stxxl::for_each, который оптимизирован для использования с контейнерами STXXL. Я бы предпочел использовать эту функцию, когда MyContainer вводится как stxxl::vector.

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

Другое решение, которое я сейчас изучаю, заключается в том, чтобы перегружать/специализировать std::foreach так, чтобы он вызывал stxxl::for_each всякий раз, когда он вызывается с stxxl::vector<Data>::(const_)iterator в качестве первого и второго аргументов.

Я не могу заставить вторую идею работать. Я пробовал следующее:

namespace std 
{ 
    template <class UnaryFunction> 
    UnaryFunction for_each(stxxl:vector<Data>::const_iterator first, 
     stxxl:vector<Data>::const_iterator last, UnaryFunction f) 
    { 
     stxxl::for_each(first, last, f, 4); 
    } 
} 

Наряду с аналогичной функцией для итераторов, не являющихся константами. Хотя их не называют.

Что было бы предпочтительным решением этой проблемы? Как я могу получить свою версию std::for_each для stxxl::vector итераторов для вызова?

Обновление: У меня есть вторая идея работать сейчас, как опубликовано. Проблема заключалась в том, что я включал неправильный файл (ouch ...). Первый вопрос остается, хотя: Какое предпочтительное решение этой проблемы? Можно ли перегрузить std :: for_each, поскольку пространство имен std не предназначено для простых смертных?

+0

Я никогда не запомню правила того, что вам разрешено вводить в std namespacem, и я уверен, что большинство других людей тоже не могут. Поэтому я предпочел бы неинвазивное решение. – 2010-01-01 16:50:41

ответ

6

Вы можете специализировать шаблоны в std (17.4.3.1), но вы не можете добавить перегрузки. Ваше определение - это перегрузка, а не специализация стандартного шаблона for_each, и в любом случае функции не могут быть частично специализированы. Таким образом, невозможно определить какое-либо определение в пространстве имен std, которое могло бы делать то, что вы хотите.

ADL должен сделать эту работу гладко, не требуя этого. Я предполагаю, что итераторы stxxl находятся в пространстве имен stxxl, поэтому for_each(first, last, f, 4); должен позвонить stxxl::for_each. Если вы хотите std::for_each, вы полностью квалифицируете имя, когда вы его вызываете.

+0

Хороший момент, не понял этого. Благодаря! –

1

std :: for_each является общедоступной хорошо документированной функцией алгоритма, я не думаю, что я намотал его, если какая-то библиотека, которую я использую, меняет ее; Возможно, другим частям моей программы нужен старый добрый for_each

Так что я бы пошел с решением, которое не нарушает этот интерфейс и оставляет std :: for_each как есть.

2

Насколько я хотел бы сказать, что вы хотите ввести в пространство имен std, это действительно липкая калитка, как указал Нил. related thread of std::swap указывает на ряд деталей, как и теперь позорный USENET discussion on the subject.

Чтобы подвести итог, единственный способ, которым вы можете ввести имя в std, - это, если вы можете полностью его специализировать. Итак, вы можете написать:

namespace std { 
    template <> 
    MyFunction for_each(stxxl::vector<Data>::const_iterator first, 
         stxxl::vector<Data>::const_iterator last, 
         MyFunction func) 
    { 
     return stxxl::for_each(first, last, func); 
    } 
} 

для каждой комбинации контейнера и функции, и вы хорошо в пределах правил. К сожалению, специализация шаблонов частичных функций не существует в текущем воплощении Стандарта. Если вам действительно интересно, посвятите вечер чтению всего USENET post. Это действительно довольно просвещает и немного пугает. Возможно, вы можете написать отличный макрос (gasp), чтобы автоматизировать это для вас, если вы используете только несколько комбинаций типов/функций.

Вы можете использовать ADL, чтобы решить эту проблему так же, как и при условии, что ни один из материалов stxxl просто не предоставляет итератор от std с помощью typedef. Я считаю, что это, как правило, предпочтительное решение сегодня.

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

+0

Это не просто ваше мнение, что оно непригодно; частичная * функция * специализация шаблона не существует, хотя это функция, которую пыталась использовать TC. –

+0

Нет такой специализации, как специализация или частичная специализация функций - только перегрузки (которые могут выглядеть так, как вы думаете, как специализация класса шаблонов) –

+0

«при условии, что ни один из элементов stxxl просто не предоставляет итератор из std с помощью typedef" , Если это так, то получение std :: for_each, вероятно, прекрасное. Нам говорят, что stxxl :: for_each - это оптимизация для контейнеров stxxl. Поэтому, если какой-то stxxl-итератор действительно является std-итератором, тогда я бы сделал ставку на то, что любые оптимизации применяются к другим итераторам stxxl, не относятся к этому. –

0

Я бы не стал специализироваться на std :: for_each().
Тем более, что вы хотите, это частичная специализация.

Скорее я бы написал функцию, которая использовала std :: for_each(), но имела специализацию для stlxxl.
У меня нет stlxxl, поэтому я сделал код, который демонстрирует, что я имею в виду.

#include <vector> 
#include <list> 
#include <algorithm> 
#include <iostream> 

// 
// Normal version. 
template<typename U,typename T,typename A,template<class I,class A> class C> 
U Ufor_each(C<T,A>& cont,U const& f) 
{ 
    std::cout << "NORMAL Start" << std::endl; 
    return std::for_each(cont.begin(),cont.end(),f); 
    return f; 
} 

// 
// Specialized version. 
// You could write a specialized version for stlxxl::vector 
template<typename U,typename T> 
U Ufor_each(std::vector<T>& cont,U const& f) 
{ 
    std::cout << "Vector Start" << std::endl; 
    return std::for_each(cont.begin(),cont.end(),f); 
} 

struct X 
{ 
    void operator()(int data) const 
    { 
     std::cout << "Item: " << data << std::endl; 
    } 
}; 

int main() 
{ 
    std::vector<int> vect; 
    std::list<int>  list; 

    vect.push_back(1); 
    list.push_back(4); 

    X     x; 
    Ufor_each(vect,x); 
    Ufor_each(list,x); 
} 

Я пробовал, но не смог заставить его работать с итераторами.

+0

Вы перегружаете Ufor_each здесь, не частично специализируясь –

1

Резюмируя:

  • Там нет такого понятия, как частичная специализация функций. Только перегрузка этой функции с вашими конкретными типами
  • Как правило, запрещается помещать материал в пространство имен std
  • Что вы действительно хотите - это перегрузить for_each в пространстве имен конкретных типов итераторов («рядом с») перегрузка. Это гарантирует, что ADL найдет его.
Смежные вопросы