[英]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.