Given:
#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);
}
Should this compile? My compilers say:
Yes: GCC/stdlibc++ (also boost::function is yes in both GCC and Clang)
No: Clang/libc++ ( http://libcxx.llvm.org/ , Clang 3.0, libc++ SVN as of today)
(If "no" is the correct answer, I will fix my real code to put complete types in more headers or use boost::function.)
EDIT: Here is the Clang error message:
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.
Clang+libc++ compiles successfully if I delete the line "worldgen_function_t w(v);" or if I make the classes complete types.
A copy constructor always takes one parameter, reference to the type for which it belongs, there maybe other parameters but they must have default values.
Hence, in a copy constructor, the parameter should always be passed as reference. Show activity on this post. If its not passed by reference then it would pass by value. If the argument is passed by value, its copy constructor would call itself to copy the actual parameter to formal parameter.
Which among the following is true for copy constructor? Explanation: It can't be defined with zero number of arguments. This is because to copy one object to another, the object must be mentioned so that compiler can take values from that object.
In C++, a Copy Constructor may be called for the following cases: 1) When an object of the class is returned by value. 2) When an object of the class is passed (to a function) by value as an argument. 3) When an object is constructed based on another object of the same class.
Edit: Apperently, this issue is now fixed, so the below text can be seen as history. :)
The issue is indeed (as I predicted) with libc++'s SFINAE checks in the templated ctor (for a reasoning, check this question). It checks if the following (for example) is valid and gives a nice and clean error at the construction site rather than deep inside the guts of std::function
(try the following example with libstd++ or MSVC... shudder):
#include <functional>
void f(int* p){}
int main(){
std::function<void(int)> fun(f);
}
libc++ will cause the compiler to spit out something along the lines of "no constructor found that matches the argument list void (*)(int*)
", since the only applicable one (the templated ctor) gets SFINAE'd out.
However, so that the __callable
and __invoke_imp
checks work, the argument and return types need to be complete, since otherwise implicit conversions wouldn't be taken into account here.
The reason that the templated ctor is even looked at is that all ctors are enumerated before considering a best match (in this case the copy ctor).
Now, the standard is very clear that the argument and return types need to be complete when constructing a std::function
object from a callable object (aka calling the templated ctor):
§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 beCopyConstructible
.f
shall be Callable (20.8.11.2) for argument typesArgTypes
and return typeR
. [...]
(Note: "Requires" addresses the user of the functionality, not the implementer.)
§20.8.11.2 [func.wrap.func] p2
A callable object
f
of typeF
is Callable for argument typesArgTypes
and return typeR
if the expressionINVOKE
(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)
whenf
is a pointer to a member function of a classT
andt1
is an object of typeT
or a reference to an object of typeT
or a reference to an object of a type derived fromT
;((*t1).*f)(t2, ..., tN)
whenf
is a pointer to a member function of a classT
andt1
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)
asINVOKE
(f, t1, t2, ..., tN)
implicitly converted toR
.
So, libc++ is certainly within its rights to do the SFINAE check in the templated ctor, since the types need to be complete, since otherwise you'd get undefined behaviour. However, it may be a bit unfortunate and be considered a defect that the safety check for a complete type triggers even if the actual SFINAE check is never needed (because the copy ctor will always be invoked). This may be alleviated by making the callable
check a lazy one, like
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);
This should only trigger the callable
SFINAE check if F
is not actually std::function<...>
.
Man, I may have digressed a bit here at the end...
I've committed a fix to libc++ such that this example now compiles, committed revision 160285.
I believe libc++ was being overly aggressive in checking the argument list for complete types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With