gpt4 book ai didi

c++ - std::function 复制构造函数是否要求模板类型参数类型是完整类型?

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:17:02 26 4
gpt4 key购买 nike

给定:

#include <functional>
class world_building_gun;
class tile_bounding_box;
typedef std::function<void (world_building_gun, tile_bounding_box)> worldgen_function_t;
void foo() {
worldgen_function_t v;
worldgen_function_t w(v);
}

这应该编译吗?我的编译器说:

是:GCC/stdlibc++(在 GCC 和 Clang 中 boost::function 也是 yes)

否:Clang/libc++(http://libcxx.llvm.org/,Clang 3.0,截至今日的 libc++ SVN)

(如果“否”是正确答案,我将修复我的真实代码以将完整类型放入更多 header 或使用 boost::function。)

编辑:这是 Clang 错误消息:

In file included from foo.cpp:2:
In file included from /usr/include/c++/v1/functional:462:
/usr/include/c++/v1/type_traits:2766:19: error: invalid appli
static_assert(sizeof(_Tp) > 0, "Type must be complete.");
^~~~~~~~~~~
/usr/include/c++/v1/type_traits:2752:15: note: in instantiation of template class 'std::__1::__check_complete<world_buildin
: private __check_complete<_Hp>,
^
/usr/include/c++/v1/type_traits:2753:15: note: in instantiation of template class 'std::__1::__check_complete<world_buildin
private __check_complete<_T0, _Tp...>
^
/usr/include/c++/v1/type_traits:2919:15: note: in instantiation of template class 'std::__1::__check_complete<std::__1::fun
world_building_gun, tile_bounding_box>' requested here
: private __check_complete<_Fp, _Args...>
^
/usr/include/c++/v1/type_traits:2930:11: note: in instantiation of template class 'std::__1::__invokable_imp<std::__1::func
world_building_gun, tile_bounding_box>' requested here
__invokable_imp<_Fp, _Args...>::value>
^
/usr/include/c++/v1/functional:1115:33: note: in instantiation of template class 'std::__1::__invokable<std::__1::function<
world_building_gun, tile_bounding_box>' requested here
template <class _Fp, bool = __invokable<_Fp&, _ArgTypes...>::value>
^
/usr/include/c++/v1/functional:1141:35: note: in instantiation of default argument for '__callable<std::__1::function<void (world_building_gun, tile_bounding_box)> >' required here
typename enable_if<__callable<_Fp>::value>::type* = 0);
^~~~~~~~~~~~~~~
/usr/include/c++/v1/functional:1140:7: note: while substituting deduced template arguments into function template 'function' [with _Fp = std::__1::function<void
(world_building_gun, tile_bounding_box)>]
function(_Fp,
^
foo.cpp:4:7: note: forward declaration of 'world_building_gun'
class world_building_gun;
^
In file included from foo.cpp:2:
In file included from /usr/include/c++/v1/functional:462:
/usr/include/c++/v1/type_traits:2766:19: error: invalid application of 'sizeof' to an incomplete type 'tile_bounding_box'
static_assert(sizeof(_Tp) > 0, "Type must be complete.");
^~~~~~~~~~~
/usr/include/c++/v1/type_traits:2753:15: note: in instantiation of template class 'std::__1::__check_complete<tile_bounding_box>' requested here
private __check_complete<_T0, _Tp...>
^
/usr/include/c++/v1/type_traits:2753:15: note: in instantiation of template class 'std::__1::__check_complete<world_building_gun, tile_bounding_box>' requested here
private __check_complete<_T0, _Tp...>
^
/usr/include/c++/v1/type_traits:2919:15: note: in instantiation of template class 'std::__1::__check_complete<std::__1::function<void (world_building_gun, tile_bounding_box)> &,
world_building_gun, tile_bounding_box>' requested here
: private __check_complete<_Fp, _Args...>
^
/usr/include/c++/v1/type_traits:2930:11: note: in instantiation of template class 'std::__1::__invokable_imp<std::__1::function<void (world_building_gun, tile_bounding_box)> &,
world_building_gun, tile_bounding_box>' requested here
__invokable_imp<_Fp, _Args...>::value>
^
/usr/include/c++/v1/functional:1115:33: note: in instantiation of template class 'std::__1::__invokable<std::__1::function<void (world_building_gun, tile_bounding_box)> &,
world_building_gun, tile_bounding_box>' requested here
template <class _Fp, bool = __invokable<_Fp&, _ArgTypes...>::value>
^
/usr/include/c++/v1/functional:1141:35: note: in instantiation of default argument for '__callable<std::__1::function<void (world_building_gun, tile_bounding_box)> >' required here
typename enable_if<__callable<_Fp>::value>::type* = 0);
^~~~~~~~~~~~~~~
/usr/include/c++/v1/functional:1140:7: note: while substituting deduced template arguments into function template 'function' [with _Fp = std::__1::function<void
(world_building_gun, tile_bounding_box)>]
function(_Fp,
^
foo.cpp:5:7: note: forward declaration of 'tile_bounding_box'
class tile_bounding_box;
^
2 errors generated.

如果我删除“worldgen_function_t w(v);”行,Clang+libc++ 编译成功或者如果我让类完成类型。

最佳答案

编辑: Apperently ,这个问题现在已经解决了,所以下面的文字可以看作是历史。 :)


问题确实(正如我预测的那样)与模板化 ctor 中的 libc++ 的 SFINAE 检查有关(为了推理,检查 this question )。它检查以下内容(例如)是否有效,并在构造 站点而不是在 std::function 的内部给出一个漂亮而干净的错误。 (使用 libstd++ 或 MSVC 尝试以下示例...不寒而栗):

#include <functional>

void f(int* p){}

int main(){
std::function<void(int)> fun(f);
}

libc++ 将导致编译器按照“未找到与参数列表 void (*)(int*) 匹配的构造函数”的行吐出一些内容,因为唯一适用的构造函数(模板化构造函数)会被 SFINAE 淘汰。

但是,__callable__invoke_imp检查工作,参数和返回类型需要完整,否则此处不会考虑隐式转换。

甚至查看模板化构造函数的原因是在考虑最佳匹配(在本例中为复制构造函数)之前枚举了所有构造函数。


现在,标准非常明确,在构造 std::function 时,参数和返回类型需要完整。来自可调用对象的对象(也称为调用模板构造函数):

§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);

Requires: F shall be CopyConstructible. f shall be Callable (20.8.11.2) for argument types ArgTypes and return type R. [...]

(注意:“要求”指的是功能的用户,而不是实现者。)

§20.8.11.2 [func.wrap.func] p2

A callable object f of type F is Callable for argument types ArgTypes and return type R if the expression INVOKE(f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well formed (20.8.2).

§20.8.2 [func.req]

p1 Define INVOKE(f, t1, t2, ..., tN) as follows:

  • (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is an object of type T or a reference to an object of type T or a reference to an object of a type derived from T;
  • ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a class T and t1 is not one of the types described in the previous item;
  • [...]
  • f(t1, t2, ..., tN) in all other cases.

p2 Define INVOKE(f, t1, t2, ..., tN, R) as INVOKE(f, t1, t2, ..., tN) implicitly converted to R.

因此,libc++ 当然有权在模板化的 ctor 中执行 SFINAE 检查,因为类型需要完整,否则你会得到未定义的行为。但是,即使从不需要实际的 SFINAE 检查(因为将始终调用复制构造函数),完整类型的安全检查也会触发,这可能有点不幸并被认为是一个缺陷。这可以通过制作 callable 来缓解。检查一个懒惰的,比如

template<bool Copy, class F>
struct lazy_callable{
static bool const value = callable<F>::value;
};

template<class F>
struct lazy_callable<true, F>{
static bool const value = false;
};

template<class F>
function(F f, typename enable_if<lazy_callable<!std::is_same<F,function>::value>::type* = 0);

这应该只会触发 callable SFINAE 检查是否F实际上不是 std::function<...> .

伙计,我可能最后跑题了……

关于c++ - std::function 复制构造函数是否要求模板类型参数类型是完整类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10730682/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com