2016-11-21 51 views
9

比方說,我有這樣定義的類FunctionWrapper防止隱式轉換,但允許列表初始化?

struct FunctionWrapper 
{ 
    FunctionWrapper(std::function<void()> f); 

    // ... plus other members irrelevant to the question 
}; 

我想,以防止隱式轉換從std::function<void()>FunctionWrapper,但允許使用大括號初始化語法(即使用列表初始化構建FunctionWrapper只有一個參數)。換句話說,我想這樣:

void foo(); 
void wrap(FunctionWrapper); 

wrap(foo); // (1) error 
wrap({foo}); // (2) OK 
wrap(FunctionWrapper{foo}); // (3) OK 

有沒有辦法做到這一點?我定義上面的類的方式不是這樣的:這允許隱式轉換,所以(1)編譯。

如果我添加explicit的構造器:

struct FunctionWrapper 
{ 
    explicit FunctionWrapper(std::function<void()> f); 

    // ... plus other members irrelevant to the question 
}; 

它並沒有幫助,因爲這雲「過猶不及」,並禁止(2)和(1)。

有沒有辦法實現「中間地帶」,並有(2)編譯while(1)產生錯誤?

+4

添加一個採用'std :: initializer_list'參數的顯式構造函數。 –

+3

你可以使用initializer_list,但那麼你將只有運行時檢查參數的數量......也許模板接受常量數組和static_assert模板大小......但只是醜陋 – Hcorg

+0

@Hcorg不會[this](http:///melpon.org/wandbox/permlink/0rFgVYD8XKYwVlC1)需要雙括號初始化? –

回答

8

有沒有辦法做到這一點?

是的。你已經擁有了它。

wrap(foo); 

對於這項工作,這將涉及到兩個用戶自定義的轉換:void(*)() --> std::function<void()> --> FunctionWrapper,但我們只允許最多一個用戶自定義轉換。所以這是一個錯誤,除非你爲FunctionWrapper添加一個單獨的構造函數來允許它。

wrap({foo}); 

這已經是很好,我們的副本列表初始化FunctionWrapper因此上述限制不適用。

wrap(FunctionWrapper{foo}); 

這顯然很好。


請注意,這也爲您的第一個示例實際工作的情況提供了一種路徑。比方說,你有:

struct Wrapper { 
    Wrapper(int) { } 
}; 

foo(0);   // want this to fail 
foo({0});   // want this to be OK 
foo(Wrapper{0}); // ... and this 

你不能讓構造explicit,因爲這會導致foo({0})失敗也是如此。但是你可以簡單與其他包裝增加一個間接的另一層:

struct AnotherWrapper { 
    AnotherWrapper(int i): i{i} { } 
    int i; 
}; 

struct Wrapper { 
    Wrapper(AnotherWrapper) { } 
}; 

這裏,wrap(0)失敗,但wrap({0})wrap(Wrapper{0})都OK。

相關問題