2013-10-20 157 views
12

我想做一個類應該繼承其他類的構造函數,但不從這些類本身繼承。如何使用std :: enable_if有條件地選擇可變參數構造函數?

在我的類的初始化期間,我想使用完美轉發來創建一個類型的對象,其構造函數與給定的參數匹配。

除了沒有參數的默認構造函數之外,不應有任何含糊之處。

這是我的代碼:

#include <string> 

using namespace std; 

//NOTE: this class is just an example to demonstrate the problem 
class String { 
    public: 
     //default constructor to prevent ambiguity 
     String() {} 

     //construct from wstring 
     template<typename... Args> 
     String(enable_if<is_constructible<wstring, Args...>::value, Args>::type&&... args) : ws(forward<Args>(args)...) {} 

     //construct from string 
     template<typename... Args> 
     String(enable_if<is_constructible<string, Args...>::value, Args>::type&&... args) : s(forward<Args>(args)...) {} 
    private: 
     string s; 
     wstring ws; 
}; 

void foo(const String& string) { 
} 

int main() 
{ 
    foo(L"123"); 
    foo("123"); 
    return 0; 
} 

我試過很多東西,但我不能得到它的工作。

  • 在目前的方案enable_if無法自動扣除模板ARGS(我認爲)
  • 由於我使用的構造我不能返回值
  • 添加其他默認參數enable_if韓元使用enable_if 「T的工作,因爲構造函數是可變參數
  • 當我從函數的參數,編譯器會抱怨無效的重載
01(當然)刪除

有沒有一種優雅的方式來解決這個問題?

編輯: 是標準允許不應該在我的課會出現一個隱式轉換。 [編輯示例代碼]

與上述示例一起工作的一種解決方案是定義單個可變參數構造函數,並將參數完美地轉發給條件初始化函數。但是,我想避免這種開銷,因爲成員需要被默認構造,並且這可能在其他情況下不起作用。

(隨意編輯的問題,如果事情可以更清楚)

+0

很好的問題,我沒有答案。 FWIW,*沒有* variadic模板它[作品](http://coliru.stacked-crooked.com/a/c799960a369ccf7e)通過使用默認參數。 –

+0

我問附近的相關問題也在:http://stackoverflow.com/questions/18700072/using-sfinae-to-select-different-method-implementations-in-a-clase-template。一個答案也是使用專業化,而不是:-) – Klaus

+0

正如我在Klaus解決方案的評論中所說:只有**一個**用戶定義的轉換是隱式執行的。無論是從字符串文字到'std :: basic_string'還是從'std :: basic_string'到你的'String'類型,但都不是兩者。 – dyp

回答

2

我無法理解的問題,也解決方案。如果我想爲方法或構造函數使用2種不同的類型,我可以簡單地編寫這兩種類型。出於這個原因,沒有必要爲SFINAE製作模板!這可以簡單地通過專業化來完成。

class A 
{ 
    public: 
    template <typename ... Args> 
    A(const wstring &, Args ...); 

    template <typename ... Args> 
    A(const string &, Args ...); 
}; 

爲了有一個模板,精確匹配的只有一種類型是不是真的語義:-)

模板閱讀您的評論後,我得到了這個解決方案:

class foo 
{ 
    public: 
     template <typename ... Args> 
     foo(const string &&x, Args ...) { cout << "Using string" << endl; } 

     template <typename ... Args> 
     foo(const wstring &&x, Args ...) { cout << "Using wstring" << endl; } 
}; 

int main() 
{ 
    foo("123"); 
    foo(L"123"); 

    foo("123", 1); 
    foo(L"123", 1.11); 
    return 0; 
} 

,這回預期:

Using string 
Using wstring 
Using string 
Using wstring 
+0

是的。這實際上適用於我目前的情況,並沒有注意到這有點令人尷尬。唯一的問題是它可能會使用一個我想要避免的隱式轉換。 – user1492625

+0

只有當參數不完全匹配時,纔會發生隱式轉換。據我瞭解你的例子,你有2個明確的定義類型。此外,如果您可以使用enable_if指定您的類型,那麼您將得到不同的效果:如果您的給定類型不完全匹配,則不會有任何導致編譯錯誤的模板實例化。 – Klaus

+0

有一個從提供的字符串文字到參數類型(wstring或string)的隱式轉換。順便說一下,如果您不另外提供rvalue-ref重載,則這是一個例子,其中一個by-value sink參數(而不是by-const-ref)的性能更高。 – dyp