2011-04-19 53 views
4

是否可以爲所有派生類型和模板構造函數定義構造函數? 我寫這個的測試用例來說明我的問題:更改構造函數優先

#include <iostream> 


class Variant; 
class CustomVariant; 


class Variant 
{ 
public: 
    Variant(void) 
     {} 


    Variant(const Variant&) 
     { 
      std::cout << "ctor" << std::endl; 
     } 


    Variant(const CustomVariant&) 
     { 
      std::cout << "custom" << std::endl; 
     } 


    template<typename T> 
    Variant(const T&) 
     { 
      std::cout << "template" << std::endl; 
     } 
}; 


class CustomVariant : public Variant 
{ 
}; 


class DerivedVariantA : public CustomVariant 
{ 
}; 


class DerivedVariantB : public CustomVariant 
{ 
}; 


int main(void) 
{ 

    DerivedVariantB dvb; 

    Variant v(dvb); 
    // expcected output: "custom" instead of "template" 

} 

回答

6
template <typename T> Variant(const T&) // (a) 
Variant(const CustomVariant&)   // (b) 

無需轉換調用(一);參數類型DerivedVariantB完全匹配,其中T = DerivedVariantB

要求調用(b)需要導出到基準的轉換。因此,(a)(b)更好匹配。

如果你調用與CustomVariant類型的參數的構造,這兩個構造函數是完全匹配,因此(B)選擇,因爲這裏的一切是平等的,非模板優於模板。

可以禁止使用其中TVariant使用std::enable_if導出模板:

template<typename T> 
Variant(const T&, 
     typename std::enable_if< 
        !std::is_base_of<Variant, T>::value, void* 
       >::type = 0) 
{ 
    std::cout << "template" << std::endl; 
} 

這使得模板時TVariant衍生沒有實例化,所以它不會是重載解析過程中可用。 enable_ifis_base_of是C++ 0x中的新增功能,您的編譯器和標準庫可能會支持它們。如果沒有,您也可以在C++ TR1或Boost.TypeTraits中找到它們。

+0

是的,那是標準定義的規則。問題是,有沒有解決方法? :) – cytrinox 2011-04-19 18:10:57

+0

有;我剛剛用一個例子更新了我的答案。 – 2011-04-19 18:11:18

+0

太好了。這是因爲SFINAE(價值沒有定義從派生類型派生)? – cytrinox 2011-04-19 18:20:56

0

不,在類的可用構造函數列表中沒有構造函數將DerivedVariantB類型的實例作爲參數。因此生成的模板被調用。現在

class DerivedVariantB ; // Forward Declaration 

class Variant 
{ 
    public: 
    // ... 

    Variant(const DerivedVariantB &obj) 
    { 
     std::cout << "\n DerivedVariantB \n"; 
    } 
}; 

,它可能調用了DerivedVariantB類型,而不是產生一個模板的參考構造函數。