std :: is_convertible与std :: function不一致

时间:2014-09-16 23:18:02

标签: c++ gcc c++11 std

当涉及到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:

  • gcc 4.8和gcc 4.9
  • clang 3.4(但不是来自ubuntu 12.04的那个)

它在以下编译器上打印1:

  • gcc 4.7
  • VC ++ 12(VS2013)
  • clang 3.2

有没有正确答案? 是编译器中的这些错误还是我搞乱编译器特定的东西?

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。对于参数类型fCallable应为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 备注:这些构造函数不应参与重载   对于参数类型,除非fCallable(20.9.11.2),否则为分辨率   ArgTypes...并返回R类型。

因此,如果您的标准库实现了此解决方案,则std::is_convertible<std::function<void(int)>, std::function<void()>>::valuefalse。否则,它依赖于实现。

  

我认为当这些函数返回true时,可以进行转换。或者我错过了什么?

类型特征(例如std::is_convertiblestd::is_constructiblestd::is_assignable仅考虑直接上下文 - 即,是否存在可访问且未删除的匹配函数签名。他们不会在实例化时检查函数体是否会编译。