当涉及到std :: function object和std :: bind时,我注意到std :: is_convertible和std :: is_assignable的一些奇怪的结果。
我认为当这些函数返回true时,可以进行转换。或者我错过了什么?
以下代码在不同的编译器上打印不同的结果,我希望它打印0,因为这些类型无法分配。
#include <type_traits>
#include <functional>
#include <iostream>
int main()
{
std::cout << std::is_convertible<std::function<void(int)>, std::function<void()>>::value << std::endl;
}
它在以下编译器上打印0:
它在以下编译器上打印1:
有没有正确答案? 是编译器中的这些错误还是我搞乱编译器特定的东西?
答案 0 :(得分:4)
在C ++ 11中,std::function
的构造函数采用任意函子类型指定为(引用N3337§20.8.11.2.1[func.wrap.func.con] / p7):
template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 需要:
F
应为CopyConstructible
。对于参数类型f
,Callable
应为ArgTypes
(20.8.11.2),并返回类型R
。该 复制构造函数和A
的析构函数不会抛出异常。
违反需要子句(为参数类型f
传递Callable
而非ArgTypes
并返回类型R
)是未定义的行为,因此,在这种情况下,图书馆可以自由地做任何事情。库可能会使构造函数超出重载分辨率,但它没有,如果没有,那么你将遇到重载分辨率和std::is_convertible
的问题 - 它将报告几乎所有的东西sun可转换为std::function
(包括double
等内容!)。
因此,在LWG issue 2132中,标准被修改为要求实现从重载决策中删除这些构造函数(通过SFINAE或类似技术)如果函数对于指定的参数类型不是Callable
和返回类型。它现在写着:
template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f);
7 需要:
F
应为CopyConstructible
。8 备注:这些构造函数不应参与重载 对于参数类型,除非
f
为Callable
(20.9.11.2),否则为分辨率ArgTypes...
并返回R
类型。
因此,如果您的标准库实现了此解决方案,则std::is_convertible<std::function<void(int)>, std::function<void()>>::value
为false
。否则,它依赖于实现。
我认为当这些函数返回true时,可以进行转换。或者我错过了什么?
类型特征(例如std::is_convertible
,std::is_constructible
或std::is_assignable
仅考虑直接上下文 - 即,是否存在可访问且未删除的匹配函数签名。他们不会在实例化时检查函数体是否会编译。