2016-11-21 50 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。

相关问题