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

tex*_*xus 5 c++ gcc std c++11

我注意到std :: is_convertible和std :: is_assignable在涉及std :: function object和std :: bind时出现了一些奇怪的结果.

我假设当这些函数返回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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • gcc 4.7
  • VC++ 12(VS2013)
  • 铿锵3.2

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

T.C*_*.C. 4

在 C++11 中,std::function采用任意函子类型的 \ 构造函数指定为(引用 N3337 \xc2\xa720.8.11.2.1 [func.wrap.func.con]/p7):

\n\n
\n
template<class F> function(F f);\ntemplate <class F, class A> function(allocator_arg_t, const A& a, F f);\n
Run Code Online (Sandbox Code Playgroud)\n\n

7要求FCopyConstructible。对于参数类型和返回类型f应为(20.8.11.2) 。的复制构造函数和析构函数不应抛出异常。CallableArgTypesRA

\n
\n\n

违反Requires子句(为参数类型和返回类型传递fnot )是未定义的行为,因此库可以在这种情况下自由地执行任何操作。该库可能会将构造函数从重载解析中取出,但它不是必须的,如果不这样做,那么您将遇到重载解析问题,并且- 它会报告几乎所有东西都是可转换的到(包括类似的东西!)。CallableArgTypesRstd::is_convertiblestd::functiondouble

\n\n

因此,在LWG 问题 2132中,标准被修改为要求实现在函子不适合Callable指定的参数类型和返回类型时从重载解析中删除这些构造函数(通过 SFINAE 或类似技术)。现在内容如下:

\n\n
\n
template<class F> function(F f);\ntemplate <class F, class A> function(allocator_arg_t, const A& a, F f);\n
Run Code Online (Sandbox Code Playgroud)\n\n

7要求FCopyConstructible

\n\n

8备注:这些构造函数不应参与重载决策,除非参数类型 和返回类型f为(20.9.11.2) 。CallableArgTypes...R

\n
\n\n

因此,如果您的标准库实现了此分辨率,std::is_convertible<std::function<void(int)>, std::function<void()>>::value那么false. 否则,它取决于实现。

\n\n
\n

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

\n
\n\n

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

\n