假设我有一个类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)编译而(1)产生错误?
答案 0 :(得分:8)
有没有办法实现这个目标?
是。你已经拥有它了。
wrap(foo);
为了实现这一点,它将涉及两个用户定义的转换:void(*)() --> std::function<void()> --> FunctionWrapper
,但我们最多只允许一个用户定义的转换。所以这是一个错误,除非你向FunctionWrapper
添加一个单独的构造函数以允许它。
wrap({foo});
这已经很好了,我们是copy-list-initializing 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})
都可以。