2016-12-24 64 views
1

假設我有一個模板類:定義專門的模板類的構造函數時避免重複

template<typename T> 
class Widget { 
public: 
    Widget(const std::string& name, int i) : t_(name), cf_(name), ci_(i) {} 
private: 
    T t_; 
    const Foo cf_; 
    const int ci_; 
} 

並假設,在此背景下,T只會Fooint。在這種情況下,除Widget<Foo>Widget<int>以外的任何內容都是無稽之談。

上面聲明的構造函數適用於Widget<Foo>。有沒有一種方法可以爲Widget<int>定義一個專門的構造函數,該函數以t_的分配方式不同,但是沒有複製 - 粘貼cf_ci_的初始化?

在精神上有點類似Base(a)Derived::Derived(int a, int b) : Base(a), b_(b) {}也許吧?

回答

5

標籤調度和轉發的構造可以幫助

template <typename> struct Tag {}; 


template<typename T> 
class Widget { 
public: 
    Widget(const std::string& name, int i) : Widget(Tag<T>{}, name, i) {} 

private: 
    Widget(Tag<int>, const std::string& name, int i) : 
     Widget(Tag<void>{}, 42, name, i) 
    {} 

    Widget(Tag<Foo>, const std::string& name, int i) : 
     Widget(Tag<void>{}, name, name, i) 
    {} 

    template <typename U> 
    Widget(Tag<void>, U&& u, const std::string& name, int i) : 
     t_(std::forward<U>(u)), 
     cf_(name), 
     ci_(i) 
    {} 

private: 
    T t_; 
    const Foo cf_; 
    const int ci_; 
}; 
1

專業整個Widget<int>類是一個選項。除此之外,有各種方法可以用來避免專門化整個班級;然而,他們在很大程度上依賴於你如何構建它。

對於這個例子,讓我們說,對於Widget<Foo>要構造類成員t_,這將使用std::string name參數是一個WidgetWidget有一個構造函數,需要一個std::string參數),併爲Widget<int>要構造現在將使用int i參數的int類成員t_

首先,定義挑選合適的參數專門幫助模板函數:

template<typename T> 
auto t_param(const std::string &name, int i); 

template<> 
auto t_param<Foo>(const std::string &name, int i) 
{ 
    return name; 
} 

template<> 
auto t_param<int>(const std::string &name, int i) 
{ 
    return i; 
} 

有了這個地方,你的構造變得簡單:

Widget(const std::string& name, int i) 
     : t_(t_param<T>(name, i)), cf_(name), ci_(i) {}