2013-06-24 2 views
2

Теперь функция «JoinStrings», которую я использую, может присоединяться только к типу данных std :: string. Мне нужно теперь присоединиться к целому числу. Поэтому я надеюсь реорганизовать его. Но я потерпел неудачу. Я рад слышать «вы не можете так поступать», потому что я действительно не знаю, разумно ли использовать эти коды таким образом или нет.Как реализовать специализированную специализацию?

вызывающую часть:

int main(int argc, char* argv[]) { 
     vector<int> integers; 
     string str = JoinStrings(integers); 
     cout << str << endl; 
} 

Часть I не удалось осуществить:

#include <string> 

template <class ConstForwardIterator> 
void JoinStrings(const ConstForwardIterator& begin, 
       const ConstForwardIterator& end, 
       const std::string& delimiter, 
       std::string* output) { 
    output->clear(); 
    for (ConstForwardIterator iter = begin; iter != end; ++iter) { 
    if (iter != begin) { 
     output->append(delimiter); 
    } 
    output->append(*iter); 
    } 
} 

// What data type should be declared for IntegerConstForwardIterator? 
template<> 
void JoinStrings(const IntegerConstForwardIterator& begin, 
       const IntegerConstForwardIterator& end, 
       const std::string& delimiter, 
       std::string* output) { 
    output->clear(); 
    for (IntegerConstForwardIterator iter = begin; iter != end; ++iter) { 
    if (iter != begin) { 
     output->append(delimiter); 
    } 
    output->append(std::to_string(*iter)); 
    } 
} 

template <class ConstForwardIterator> 
std::string JoinStrings(const ConstForwardIterator& begin, 
         const ConstForwardIterator& end, 
         const std::string& delimiter) { 
    std::string output; 
    JoinStrings(begin, end, delimiter, &output); 
    return output; 
} 

template <class Container> 
std::string JoinStrings(const Container& container, 
         const std::string& delimiter = " ") { 
    return JoinStrings(container.begin(), container.end(), delimiter); 
} 
+0

не удалось как? вы получили ошибки компилятора или неожиданное поведение? – kfsone

+2

Интуитивно я предлагаю вам не использовать 'std :: string' для генерации вывода, а' std :: ostringstream'. Это позволило бы решить многие проблемы - в частности, вам даже не понадобилась бы специализация шаблона для 'int'. – jogojapan

+0

Хорошо, я пытаюсь. Кстати, есть ли потеря эффективности? – Mou

ответ

0

Можно изменить код, чтобы достичь того, чего вы хотите. Я интерпретирую этот вопрос как упражнение по шаблонной специализации. (Для рекомендуемой альтернативы, следовать комментарий jogojapan в)

Предисловие: Я ожидал, что это сработает, но (хотя он компилирует) это не потому, что общая версия еще лучше матч:

template<template <class> class Cont > 
void JoinStrings(const typename Cont<int>::const_iterator& begin, 
       const typename Cont<int>::const_iterator& end, 
       const std::string& delimiter, 
       std::string* output) { 
    std::clog << "specialized called" << std::endl; 
    .... 
} 

Итак, мне пришлось прибегнуть к добрым старым enable_if (я использую C++ 11 для краткости здесь, с некоторыми усилиями можно сделать в C++ 98). С кодом main вызывается специализированная версия.

Решение

#include<type_traits> 
.... 
template <class ConstForwardIterator, 
    class = typename std::enable_if<not std::is_same<typename std::decay<decltype(*std::declval<ConstForwardIterator>())>::type, int>::value>::type 
> 
void JoinStrings(const ConstForwardIterator& begin, 
       const ConstForwardIterator& end, 
       const std::string& delimiter, 
       std::string* output) { 
    std::clog << "generic called" << std::endl; 
    std::clog << std::trace() << std::endl; 
} 

template <class ConstForwardIterator, 
    class = typename std::enable_if<std::is_same<typename std::decay<decltype(*std::declval<ConstForwardIterator>())>::type, int>::value>::type, 
    class Tag = void 
> 
void JoinStrings(const ConstForwardIterator& begin, 
       const ConstForwardIterator& end, 
       const std::string& delimiter, 
       std::string* output) { 
    std::clog << "special called" << std::endl; 
    .... 
} 

Более классическое решение является использование "Tag диспетчерскую" http://www.boost.org/community/generic_programming.html#tag_dispatching, но requieres изменить больше кода, как ваш Container-версии JoinString.

Ограниченного решение: В случае, если вы ожидаете код для работы только с std::vector Решения намного проще:

template <> 
void JoinStrings(const std::vector<int>::const_iterator& begin, 
       const std::vector<int>::const_iterator& end, 
       const std::string& delimiter, 
       std::string* output) 
+0

ОК, я рад это слышать. Ваша точка - рефакторинг, так как это не повторно или не практично. – Mou

+0

@Mou, я не пытался ни о чем. Просто попытался написать что-то похожее на специализацию. – alfC

0

Является ли это то, что вы хотите? Как сказал @jogojapan, использование std :: ostringstream - лучший выбор.

#include <vector> 
#include <string> 
#include <iostream> 
#include <sstream> 

template <class ConstForwardIterator> 
std::string JoinStrings(const ConstForwardIterator& begin, 
     const ConstForwardIterator& end, 
     const std::string& delimiter) { 
    std::ostringstream oss; 
    for (ConstForwardIterator iter = begin; iter != end; ++iter) { 
     if (iter != begin) { 
      oss << delimiter; 
     } 
     oss << *iter; 
    } 
    return oss.str(); 
} 

template <class Container> 
std::string JoinStrings(const Container &container, 
     const std::string& delimiter = " ") { 
    return JoinStrings(container.begin(), 
      container.end(), delimiter); 
} 

int main(int argc, char *argv[]) { 
    std::vector<int> integers; 
    integers.push_back(1); 
    integers.push_back(2); 
    integers.push_back(3); 
    std::string str = JoinStrings(integers); 
    std::cout << str << std::endl; 

    std::vector<std::string> strings; 
    strings.push_back("MOU"); 
    strings.push_back("BI"); 
    str = JoinStrings(strings); 
    std::cout << str << std::endl; 
    return 0; 
} 
+1

Извините, это мне не нужно. Мне нужно «не разумно» или «тип IntegerConstForwardIterator», а функциональная реализация по-другому. – Mou

Смежные вопросы