簡體   English   中英

接受stl_container_type的模板化參數 <string> ::迭代

[英]Accept templated parameter of stl_container_type<string>::iterator

我有一個函數,我有一個容納字符串的容器(例如vector<string>set<string>list<string> ),並且給定一個啟動迭代器和一個結束迭代器,遍歷處理字符串的迭代器范圍。

目前該函數聲明如下:

template< typename ContainerIter>
void ProcessStrings(ContainerIter begin, ContainerIter end);

現在,這將接受符合實現operator* ,前綴operator++和函數體中任何其他調用的隱式接口的任何類型。

我真正想做的是有一個像下面那樣明確限制輸入量的定義(偽代碼警告):

template< typename Container<string>::iterator>
void ProcessStrings(Container<string>::iterator begin, Container<string>::iterator end);

所以我可以這樣使用它:

vector<string> str_vec;
list<string> str_list;
set<SomeOtherClass> so_set;

ProcessStrings(str_vec.begin(), str_vec.end());  // OK
ProcessStrings(str_list.begin(), str_list.end());  //OK
ProcessStrings(so_set.begin(), so_set.end());  // Error

本質上,我想要做的是限制函數規范,使函數的用戶明白它接受的內容,如果代碼編譯失敗,他們會得到一條消息,他們使用了錯誤的參數類型而不是XXX類無法找到XXX函數的函數體。

您可以使用模板模板參數來接近此:

template<template<class> class CONTAINER>
void ProcessStrings(CONTAINER<string>&);

這將處理整個容器,如果它不包含字符串,則會產生編譯錯誤。

ProcessStrings(str_vec); // OK
ProcessStrings(so_set); // Error

如果你想使用迭代器范圍,那么我能管理的最好的是

template<template<class> class CONTAINER>
void ProcessStrings(typename CONTAINER<string>::iterator, 
                    typename CONTAINER<string>::iterator);

不幸的是,類型推斷不適用於函數參數,因此您必須明確地給出模板參數:

ProcessStrings<vector>(str_vec.begin(), str_vec.end()); // OK
ProcessStrings<set>(so_set.begin(), so_set.end()); // Error

任何人都可以改進嗎?

您可以使用boost::enable_if模板魔術來實現此類檢查。 除非迭代器的值類型是string類型,否則不會編譯下面的方法。

template<class It>
boost::enable_if_c< 
        boost::is_same< typename boost::iterator_value<It>::type, string >::value
>::type
ProcessStrings(It itBegin, It itEnd) 
{ }

如果boost::iterator_value<It>::type的類型為string,則boost::enable_if<...>::type將評估為void,即返回參數。 否則,由於SFINAE(替換失敗不是錯誤)原則,該方法將在沒有錯誤的情況下編譯。

一種簡單但有效的方法。

template <class T>
struct is_basic_string: boost::mpl::false_ {};

template <class CharT, class Traits, class Alloc>
struct is_basic_string< std::basic_string<CharT, Traits, Alloc> >:
   boost::mpl::true_ {};

然后用它來檢查值類型

void ProcessStrings(Iterator begin, Iterator end)
{
  BOOST_MPL_ASSERT_MSG(
    is_basic_string< typename boost::value_type<Iterator>::type >,
    ONLY_ACCEPT_ITERATOR_TO_BASIC_STRING,
    (Iterator)
  );

  // do your work
}

檢查此處的引用,此宏旨在在編譯時提供盡可能有意義的消息。

這也Sebastian解決方案更通用......但是std::wstring對於國際化std::wstring非常方便,你不會想要扼殺它。

現在非常好的問題是......你為什么要那樣做!

泛型編程的目標是生成可以使用符合其內部操作的任何類型的函數。 你為什么要故意限制這個?

嘗試

#include <string>
#include <vector>
#include <list>

template<template<typename T,typename A> class C>
void ProcessStrings(typename C<std::string, std::allocator<std::string> >::iterator begin,
                    typename C<std::string, std::allocator<std::string> >::iterator end)
{
}


int main()
{
    std::vector<std::string>    strVec;
    std::list<std::string>      strList;
    std::list<int>              intList;

    ProcessStrings<std::vector>(strVec.begin(), strVec.end());
    ProcessStrings<std::list>(strList.begin(), strList.end());
    ProcessStrings<std::list>(intList.begin(), intList.end());  // This will fail
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM