2010-03-12 57 views
12

假設我們有一個模板函數「富」:一個模板特多類

template<class T> 
void foo(T arg) 
{ ... } 

我可以專門針對某些特定的類型,例如

template<> 
void foo(int arg) 
{ ... } 

如果我想對所有內置數值類型(int,float,double等)使用相同的特化,我會多次寫這些行。我知道這個機構可以拋出到另一個函數,只需要調用這個函數就可以在每個專業化的機構中進行調用,但是如果我可以避免寫這個「void foo(...)」,每種類型都會更好。任何可能性告訴編譯器,我想用這種專業化的所有這類型?

+3

你的最終目標是什麼? –

+0

這不是直接的答案,但它涵蓋了專業化與超載並可能會讓你感興趣:http://www.gotw.ca/publications/mill17.htm – sellibitze

回答

19

您可以使用std::numeric_limits來查看某個類型是否爲數值類型(對於所有浮點和整數基本類型,is_specialized均爲真)。

// small utility 
template<bool> struct bool2type { }; 

// numeric 
template<typename T> 
void fooImpl(T arg, bool2type<true>) { 

} 

// not numeric 
template<typename T> 
void fooImpl(T arg, bool2type<false>) { 

} 

template<class T> 
void foo(T arg) 
{ fooImpl(arg, bool2type<std::numeric_limits<T>::is_specialized>()); } 
+0

乾淨的主意!但爲什麼不只是讓'fooImpl'依賴於一個類型和一個布爾參數呢? – Vlad

+1

@Vlad因爲我們想要編譯時分支。如果我們傳遞一個'bool'函數參數,我們將在相同的函數中執行代碼並使用'if'來分支。不幸的是,這兩個分支都會進行類型檢查,很可能會錯過目標。 –

+0

@Johannes:我的意思是兩個模板參數,只是爲了省略'bool2type'的定義。 – Vlad

0

也許你可以定義默認模板功能,將所有原生類型的工作,並委託定製型的專業化用戶

3

您可以使用預處理器的方法。

foo.inc:

template<> 
void foo(TYPE arg) 
{ /* do something for int, double, etc. */ } 

了foo.h:

template<class T> 
void foo(T arg) 
{ /*do something */ } 

#define TYPE int 
#include "foo.inc" 
#undef TYPE 

#define TYPE double 
#include "foo.inc" 
#undef TYPE 

3

有了提升:

#include <boost/type_traits/is_scalar.hpp> 
#include <iostream> 
#include <string> 

namespace detail 
{ 
    typedef const boost::true_type& true_tag; 
    typedef const boost::false_type& false_tag; 

    template <typename T> 
    void foo(const T& pX, true_tag) 
    { 
     std::cout << "special: " << pX << std::endl; 
    } 

    template <typename T> 
    void foo(const T& pX, false_tag) 
    { 
     std::cout << "generic: " << pX << std::endl; 
    } 
} 

template <typename T> 
void foo(const T& pX) 
{ 
    detail::foo(pX, boost::is_scalar<T>()); 
} 

int main() 
{ 
    std::string s = ":D"; 
    foo(s); 
    foo(5); 
} 

你可以很容易地多爲做到這一點,而不提升:

#include <iostream> 
#include <string> 

// boolean stuff 
template <bool B> 
struct bool_type {}; 

typedef bool_type<true> true_type; 
typedef bool_type<false> false_type; 

// trait stuff 
template <typename T> 
struct is_scalar : false_type 
{ 
    static const bool value = false; 
}; 

#define IS_SCALAR(x) template <> \ 
      struct is_scalar<x> : true_type \ 
      { \ 
       static const bool value = true; \ 
      }; 

IS_SCALAR(int) 
IS_SCALAR(unsigned) 
IS_SCALAR(float) 
IS_SCALAR(double) 
// and so on 

namespace detail 
{ 
    typedef const true_type& true_tag; 
    typedef const false_type& false_tag; 

    template <typename T> 
    void foo(const T& pX, true_tag) 
    { 
     std::cout << "special: " << pX << std::endl; 
    } 

    template <typename T> 
    void foo(const T& pX, false_tag) 
    { 
     std::cout << "generic: " << pX << std::endl; 
    } 
} 

template <typename T> 
void foo(const T& pX) 
{ 
    detail::foo(pX, is_scalar<T>()); 
} 

int main() 
{ 
    std::string s = ":D"; 
    foo(s); 
    foo(5); 
} 
0

您可以編寫一個小腳本(例如Perl)爲您生成源文件。創建一個包含你想要專門化的所有類型的數組,並讓它爲每個類型寫出函數頭。您甚至可以將腳本執行嵌入到makefile中,以便在您更改某些內容時自動重新運行該腳本。

注意:這裏假設foo的實現可以變得很簡單,並且對於每種類型都是相似的,例如,簡單地調用真正的實現函數。但是它避免了一堆模板/預處理器的巨無霸,這可能會使未來的維護者搔首弄溼。