2013-03-06 28 views
0

下面是一個有缺陷的(和簡化的)模板函數,希望能夠在可以轉換爲預定義數量的類型之一的模板arg上工作。獲取C++編譯器以揭示什麼類型可以轉換爲

它恰好是2種類型,但它更冷。

void do_something_type_specific(const int &unused) { std::cout << 'i'; } 
void do_something_type_specific(const std::string &unused) { std::cout << 's'; } 

template< typename Iterator > 
void perform_work_on_a_range(Iterator begin, Iterator end) 
{ 
    do_something_type_specific(*begin); 
    // Perhaps more code... 
} 

這發生在我的環境中產生所需的結果。 模板實例將成功編譯iff *Iterator產生可轉換爲其中一個選項的類型。

但是,該代碼不必要求執行轉換,並且儘管unused未被使用,但當begin == end仍然存在UB。

如何在C++ 03中實現這種行爲而沒有這些問題?

+3

我認爲這很可能與SFINAE完成。 – 2013-03-06 16:49:57

+0

據我所知,C++ 03只提供了一個「簡單」的運行時,在那裏沒有辦法看到一個類型可以轉換成什麼。它是一種靜態語言,除了一點運行時多態。 – 2013-03-06 16:50:40

+1

@ bash.d什麼類型可以轉換爲靜態信息(請記住,C++是一種靜態語言!)。我不明白爲什麼運行時會參與其中。 – 2013-03-06 16:51:55

回答

3

而不是取消引用迭代器,我的結果在begin == end時導致未定義的行爲,您可以嘗試使用std::iterator_traits<>。例如: -

#include <iterator> 
#include <string> 
#include <cstdio> 

void do_something_type_specific(std::string const&) { printf("%s\n", __PRETTY_FUNCTION__); } 
void do_something_type_specific(int const&) { printf("%s\n", __PRETTY_FUNCTION__); } 

template<class T> 
struct ProduceValue 
{ 
    static T value; 
}; 

template<class T> 
T ProduceValue<T>::value; 

// Specializations for types that can't be default constructed or must be initialized. 
template<> 
char* ProduceValue<char*>::value = ""; 

template< typename Iterator > 
void perform_work_on_a_range(Iterator begin, Iterator end) 
{ 
    typedef typename std::iterator_traits<Iterator>::value_type value_type; 
    do_something_type_specific(ProduceValue<value_type>::value); 
} 

int main() { 
    char** p = 0; 
    perform_work_on_a_range(p, p); 

    long* q = 0; 
    perform_work_on_a_range(q, q); 
} 

輸出:

void do_something_type_specific(const string&) 
void do_something_type_specific(const int&) 

唯一不方便的是,ProduceValue<T>必須專門用於類型不能默認構造或者必須爲其他原因(如char*)來初始化。

+0

我是一個專家,甚至我無法弄清楚如何使用它來避免UB。 – Puppy 2013-03-06 17:01:28

+0

@DeadMG @DeadMG你基本上只是把你的專家稱號放在線上,就像所有人一樣) – 2013-03-06 17:02:56

+1

@DeadMG例如,你可以使用'iterator_traits <> :: value_type'和'boost :: is_convertible'來將元函數寫入確定值類型是否可轉換,而不是取消引用迭代器。或者可以用'(value_type *)0'指針調用一個函數。 – dhavenith 2013-03-06 17:07:05

2

有一個boost::is_convertible元函數,你可以用它來確定一個類型T可以轉換成一些其他類型的U.

其次,爲begin == end,只需插入一個運行時檢查。

+0

「for begin == end,只需插入一個運行時檢查」,這將改變行爲,不是嗎?應該調用哪個'do_something_type_specific'呢? – 2013-03-06 16:54:53

+3

@DrewDormann:你在'begin == end'時要求它沒有UB。這改變了行爲。所以它符合要求。你不知道是否'開始==結束'沒有檢查。 – Puppy 2013-03-06 16:56:36

+0

在那種情況下應該調用哪個'do_something_type_specific()'? – 2013-03-06 16:58:30

0

你可能想要做這樣的事情,而不是:

template <typename T> 
void do_something_type_specific() {} 
template <> 
void do_something_type_specific<int>() {...} 
template <typename Iterator> 
void perform_work_on_a_range(Iterator begin, Iterator end) { 
    do_something_type_specific<typename Iterator::value_type>(); 
} 
+1

如果'Iterator :: value_type'被稱爲'short',應該調用'int'版本,因爲'short'可以轉換爲'int'。 – 2013-03-06 17:26:18

1

的問題有問題的代碼試圖利用這兩個模板參數功能參數的特點。

函數參數允許類型轉換,但需要實例化類型。模板參數不需要實例化,但也不需要執行類型轉換。

下面的模式使用Boost的enable_ifis_convertible來允許編譯器選擇模板函數,就好像模板參數支持與函數參數相同的類型轉換規則一樣。(您的建議謝謝@dhavenith)

#include <boost/utility.hpp> 
#include <boost/type_traits.hpp> 

// enable_if_c makes the return type either void or a Substitution Failure. 
template < typename T> 
typename boost::enable_if_c<boost::is_convertible<T,int>::value>::type 
do_something_type_specific() 
{ 
    std::cout << 'i'; 
} 

template < typename T> 
typename boost::enable_if_c<boost::is_convertible<T,std::string>::value>::type 
do_something_type_specific() 
{ 
    std::cout << 's'; 
} 

template< typename Iterator > 
void perform_work_on_a_range(Iterator begin, Iterator end) 
{ 
    // This code is from @MaximYegorushkin's answer. Vote him up :) 
    typedef typename std::iterator_traits<Iterator>::value_type value_type; 
    do_something_type_specific<value_type>(); 
    // Perhaps more code... 
} 

這已被證實與@ MaximYegorushkin的樣本爲主。

int main() { 
    char** p = 0; 
    perform_work_on_a_range(p, p); 

    long* q = 0; 
    perform_work_on_a_range(q, q); 
} 

輸出:

si 
+1

這很優雅。 – 2013-03-06 19:09:23

相關問題