I've recently learned that C++ can perform implicit function-to-function-pointer cast whenever it found necessary. For example, in my example below, my_func_1
and my_func_2
are equivalent. However, vector_1
and vector_2
are not, and in fact, vector_2
will give a compile error. Similar compile errors also happen for other standard containers, eg unordered_map
. Why is it so?
class my_class {
// dummy class
};
int main() {
vector<my_class(*)()> vector_1; // correct one
vector<my_class()> vector_2; // gives compile error
// However, both of the below are OK due to implicit
// function-to-function-pointer conversion
void my_func_1(my_class(*)());
void my_func_2(my_class()); // equivalent to the one above
}
Here is the compile error message (shortened to highlight the error):
/usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:96:7: error: multiple overloads of 'address' instantiate to the same signature '__gnu_cxx::new_allocator<my_class ()>::const_pointer (__gnu_cxx::new_allocator<my_class ()>::const_reference) const noexcept' (aka 'my_class (*(my_class (&)()) const noexcept)()') address(const_reference __x) const _GLIBCXX_NOEXCEPT ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/allocator.h:112:30: note: in instantiation of template class '__gnu_cxx::new_allocator<my_class ()>' requested here class allocator: public __allocator_base<_Tp> ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/alloc_traits.h:49:47: note: in instantiation of template class 'std::allocator<my_class ()>' requested here template<typename _Alloc, typename = typename _Alloc::value_type> ^ /usr/bin/../lib/gcc/x86_64-linux-g nu/9/../../../../include/c++/9/bits/stl_vector.h:83:35: note: in instantiation of default argument for '__alloc_traits<std::allocator<my_class ()>>' required here typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template ^~~~~~~~~~~~~~~~~~~~~~ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/stl_vector.h:386:30: note: in instantiation of template class 'std::_Vector_base<my_class (), std::allocator<my_class ()>>' requested here class vector: protected _Vector_base<_Tp, _Alloc> ^ Line 7: Char 24: note: in instantiation of template class 'std::vector<my_class (), std::allocator<my_class ()>>' requested here vector<my_class()> vector_2; // gives compile error ^ /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/ext/new_allocator.h:92:7: note: previous declaration is here address(reference __x) const _GLIBCXX_NOEXCEPT ^
In this declaration:
vector<my_class()> vector_2;
the type used to instantiate the vector is myclass()
, which is a function type. Specifically it's a function that takes no arguments, and returns a my_class
.
A function type is not copy-assignable , as can be seen from this test:
static_assert(not std::is_copy_assignable_v<Foo()>);
Being copy-assignable is one of the requirements on the type used as a template parameter for std::vector
, and so this declaration doesn't compile.
The remaining declarations are fine:
vector<my_class(*)()> vector_1; // vector of function pointer type
Due to implicit conversion to function-pointers of types used in function parameters, the following declarations are equivalent:
void my_func_1(my_class(*)()); // function taking a function pointer
// to a function that takes no arguments
// and returns a my_class
void my_func_2(my_class()); // function taking a function that takes no
// arguments and returns a my_class
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.