2015-07-01 47 views
1

我想以某種方式爲一個類創建構造函數,以便編譯器在需要時輕鬆地創建它的新實例。SFINAE重複的構造函數聲明

下面是一個例子。

class C { 
    public: 
    C(int) {}; // int constructor 
}; 

如果我再聲明函數:

void F(C _c) {}; 

我可以稱之爲一個與int和對C編譯器處理的建設:

F(0); // works 

我想要什麼要做的是實現同樣的事情,但以lambda爲參數,舉幾個例子:

F([]() {});      //A 
F([](int) {});     //B 
F([](int)->int { return 0; }); //C 

隨着SFINAE並從我從另一個問題獲悉:Auto-constructor not working with <functional> objects

我設法理清一種方法來創建,只有特定的λ簽名匹配構造函數,它會制定出這樣的:

template<typename F, typename = decltype(function<void(void)>(declval<F&>()))> C(F&& f) {}; //For lambda's like A 
template<typename F, typename = decltype(function<void(int)>(declval<F&>()))> C(F&& f) {}; //For lamdba's like B 
template<typename F, typename = decltype(function<int(int)>(declval<F&>()))> C(F&& f) {}; //For lambda's like C 

現在我有的問題是,如果我一次添加這三個定義,我得到一個錯誤,指出我試圖重新定義C的構造函數。這是正確的,因爲,是的,構造函數被定義爲C(F & & f)三次,但是,我應該如何讓編譯器知道使用不同的符號針對每種不同的情況?

另一個答案暗示我要看看enable_if和is_convertible,但還沒有設法解決這個問題。任何幫助是極大的讚賞。

使用:蘋果LLVM 6.0版(鐺 - 600.0.57)(基於LLVM 3.5svn)

+0

http://stackoverflow.com/questions/15427667/sfinae-working-in-return-type-但不是作爲模板參數 –

回答

1

您當前的問題是,你定義3次

template <typename F, typename> C(F&&); 

,但不同的默認參數(做SFINAE)。

您可能會更改爲

// Use to have different type easily 
template <std::size_t> struct dummy {} 

template<typename F, decltype(function<void(void)>(declval<F&>()), dummy<0>())* = nullptr> C(F&& f); 
template<typename F, decltype(function<void(int)>(declval<F&>()), dummy<1>())* = nullptr> C(F&& f); 
template<typename F, decltype(function<int(int)>(declval<F&>()), dummy<2>())* = nullptr> C(F&& f); 

所以,你有3個不同的簽名:

template<typename F, dummy<0>*> C(F&& f); 
template<typename F, dummy<1>*> C(F&& f); 
template<typename F, dummy<2>*> C(F&& f); 
+0

謝謝@ Jarod42,爲什麼當我省略「= nullptr」時會失敗? – almosnow

+1

@almosnow:如果你省略'= nullptr',你必須提供一個有效的參數('dummy *') – Jarod42

1

基於top answer here,這是我想出了。它可能有點粗糙,可以改進,但它的主要作用(嘗試在線鏗鏘3.5.0)。

template <typename T> 
struct function_traits 
    : public function_traits<decltype(&T::operator())> 
{}; 

template <typename ClassType, typename ReturnType, typename... Args> 
struct function_traits<ReturnType(ClassType::*)(Args...) const> 
{ 
    typedef ReturnType(signature)(Args... args); 
    typedef ReturnType(*ptr_signature)(Args... args); 
}; 


class C 
{ 
public: 
    template<typename F> C(F&& f) { 
     typedef function_traits<F> traits; 
     I<F>(std::move(f), reinterpret_cast<typename traits::ptr_signature>(0)); 
    } 

    template<typename F> void I(F&& f, void(*)()) { std::cout << "Hello void(void) lambda" << std::endl; }; 
    template<typename F> void I(F&& f, void(*)(int)) { std::cout << "Hello void(int) lambda" << std::endl; }; 
    template<typename F> void I(F&& f, int(*)(int)) { std::cout << "Hello int(int) lambda" << std::endl; }; 
}; 

int main() 
{ 
    C([](int i) { return i;}); 
    C([](int i) {}); 
    C([]() {}); 
} 
+0

感謝亞歷克斯,我接受Jarod的簡單回答,但你的也很好。 – almosnow