2015-05-29 91 views
9

我想有這應該由給定的初始化函數初始化嵌套值模板:專營模板與函數指針,這取決於模板參數

template <typename T, T(INIT)()> struct Foo 
{ 
    T value = INIT(); 
}; 

可以這樣使用:

// Some random type only instanceable through factory() 
struct Bar 
{ 
    int bar{}; 
private: 
    // The only way to create a Bar is through factory() 
    friend Bar factory(); 
    Bar() {}; 
}; 

Bar factory() { return {}; } 

Foo<Bar, factory> foo; 

但是,如果沒有提供的功能,模板應儘量默認初始化嵌套的價值,所以我試圖專注模板:

template <typename T> struct Foo<T, nullptr> 
{ 
    T value{}; 
}; 

的想法是使用這種方式:

struct Baz{}; 

Foo<Bar, factory> foo; // Nested Bar have Bar::bar initialized through factory function. 
Foo<Baz>   baz; // No factory function needed, nested Baz default-initialized. 

但我剛剛發現模板部分特例類型不能依賴於其他模板類型,我得到的錯誤被粘貼如下:

error: type 'T (*)()' of template argument 'nullptr' depends on a template parameter template struct Foo


有沒有辦法實現我的目標?

template <typename T, T(INIT)()> T Foo = INIT(); 
template <typename T>   T Foo<T, nullptr>{}; 

額外的問題:爲什麼部分特例不能依賴於模板參數,如果它與模板變量的作品,以及這將是很好?這個限制背後的理由是什麼?

回答

2

如果只是在缺少第二個模板參數的情況下進行默認初始化,則可以提供模板化默認初始化函數作爲默認參數。

template<typename T> 
    T do_default_assign() { 
     return T(); 
    };                  

template <typename T, T (INIT)() = do_default_assign<T> > struct Foo 
    { 
     T value = INIT(); 
    }; 

然而,這遭受不必要「的價值迴歸」和賦值操作這可能是一些T.

+0

接受這一個,沒有從@ Jarod42中的一個,因爲它是在1秒前回答的! –

3

對於你的情況昂貴的或不可能的,你可以使用:

template <typename T> 
T default_construct() { return T{}; } 

template <typename T, T(INIT)() = &default_construct<T>> 
struct Foo 
{ 
    T value = INIT(); 
}; 

而且然後用它喜歡:

Foo<int> f; 
Foo<int, bar> b; 

Live demo

2

可以定義一個constructor模板功能,將初始化Type類型的值,然後把它作爲一個默認的構造函數:

template<typename Type, typename... Args> 
Type constructor(Args... args) { 
    return Type(std::forward<Args>(args)...); 
} 

,然後用它作爲函數的默認模板參數:

template <typename T, T(INIT)() = constructor<T>> struct Foo 
{ 
    T value = INIT(); 
}; 

Live demo

+0

這種方法看起來不錯,因爲它允許將任何參數傳遞給構造函數,但是提供與'T(INIT)()'不兼容的'構造函數'是不可能的,所以最後:將所有'Args'轉發給'構造函數'沒有意義:( –

+0

@PaperBirdMaster真的,但現在你有一個更通用的'構造函數',它是一個有用的函數,可以用於任何類型的構造函數(用於其他目的),而不是硬編碼的'default_construct'或者像其他人所建議的那樣使用'do_default_assign'。 – Shoe