Lets assume that we have a function
int foo (std::string, size_t = 0) { return 42; }
and I would like to call this function using wrapper function
template <typename T>
auto boo (std::string s) {
return (*T::value) (s);
}
So, T should contain a pointer to appropriate function, so I declare it like this
struct Foo : std::integral_constant<int (*) (std::string, size_t), &foo> {};
and now the usage looks like this
std::cout << boo<Foo> ("b") << "\n"; // 42
On GCC 5.3.1 this code compiles fine but on GCC 6.3.1 and GCC 7.2.1 this fails to compile with an error
error: too few arguments to function
As far as I am concerned if I use a pointer to a function without wrapper template function
using Ptr = int (*) (std::string, size_t);
Ptr p = &foo;
auto x = p ("10");
then the error is present in all mentioned versions of GCC.
According to the latter example, does it mean that I can not use a pointer without explicitly specifying second argument even though pointed function does not need it?
According to the main example does it mean that GCC 5.3.1 incorrectly implements this behavior in connection with template wrapper?
It's fine to use a function with default arguments using any of its possible signatures, but you've introduced an inconsistency yourself. You've specifically defined Foo as wrapping a pointer to a two-argument function, so you'd better call it with two arguments. If you want to call it with one argument, use it as a pointer to a one-argument function.
I'm not sure what you're trying to accomplish with integral_constant.
Related
Suppose I have a function that performs some side effect and then returns an answer:
int foo()
{
perform_some_side_effect();
return 42;
}
I want to bind foo to a function pointer, but I'm not interested in the answer, just the side effect:
void (*bar)() = foo;
However, this appears to be a type error:
error: invalid conversion from ‘int (*)()’ to ‘void (*)()’
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
On a side note, it works if I wrap the function pointer in a std::function:
std::function<void()> baz = foo;
How does std::function (apparently) manage to circumvent this restriction in the type system?
What is the rationale behind that error? Why doesn't the type system allow me to ignore the answer?
The reason is that the types are different, and the generated code at the place of call (through the function pointer) is different. Consider a calling convention where all arguments are written to the stack and space for the return value is also reserved in the stack. If the call goes through a void (*)() then no space will be reserved in the stack for the return value, but the function (unaware of how it is being called) will still write the 42 to the location where the caller should have reserved space.
How does std::function (apparently) manage to circumvent this restriction in the type system?
It does not. It creates a function object that wraps the call to the actual function. It will contain a member like:
void operator()() const {
foo();
}
Now when the compiler processes the call to foo it knows what it has to do to call a function that returns an int and it will do so according to the calling convention. Because the template does not return, it will just ignore the value --that was actually returned.
std::function need only be source compatible- that is, it can generate a new class which generates new caling code that ignores the result. The function pointer must be binary compatible and cannot do that job- void(*)() and int(*)() point to the exact same code.
You can think of std::function<> doing this for your particular case:
void __func_void()
{
foo();
}
It's actually a bit more complicated than that, but the point is that it generates template code together with type-erasure to not care about the specifics.
In addition to what others have been saying, the caller also need the return type to know what destructor it should invoke on the result (the return value may be a temporary).
Unfortunately it is not as easy as
auto (*bar)() = foo;
Although GCC and Clang accept this. I need to recheck the spec to see whether that's actually correct.
Update: The spec says
The auto type-specifier signifies that the type of a variable being declared shall be deduced from its initializer or that a function declarator shall include a trailing-return-type.
This can be misleading when read fast, but this is implemented by GCC and clang to only apply to the toplevel declarator. In our case, this is a pointer declarator. The declarator nested in it is a function declarator. So just substitute auto for void and then the compiler will deduce the type for you.
By the way, you can always make this work manually, but it takes some trickery to make it work
template<typename FunctionType>
struct Params;
template<typename ...Params>
struct Params<void(Params...)> {
template<typename T>
using Identity = T;
template<typename R>
static Identity<R(Params...)> *get(R f(Params...)) {
return f;
}
};
// now it's easy
auto bar = Params<void()>::get(foo);
My previous question concluded that a distasteful "double cast" might be necessary to use the POSIX makecontext with a C++ lambda function (i.e. function object). Moving on, I'm now faced with a compilation error relating to the following minimal code:
#include <iostream>
#include <ucontext.h>
using namespace std;
template <typename T> void foo() {
ucontext_t c;
auto f = [=](int i){ cout << i << endl; };
makecontext(&c, (void (*) (void)) (void (*)(int)) f, 1, 12345);
}
int main(int argc, char *argv[]) {
foo<int>();
return 0;
}
The error is:
error: invalid cast from type ‘foo() [with T = int]::<lambda(int)>’ to type ‘void (*)(int)’
However, if I remove the unused (in this example) template argument from the foo function, so it becomes void foo();, and change the call to foo() the error disappears. Could someone tell me why? I'm using G++ 4.6.
Edit:
From the comments below, it seems the [=] in the code above causes the lambda to be a "capturing" lambda, regardless of the fact that it doesn't actually capture anything. The [=] is not necessary in my code, alas replacing with [] in GCC 4.6 does not remove the error. I am installing GCC 4.6.1 now...
If you use [=] to induce your lambda, you will not get a function pointer (or an object that is convertible to one). You will get a function object. And no amount of casting is going to allow you to pass that to makecontext. Not in any way that actually works.
According to N3291, the most recent working draft of C++0x:
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.
This is the only place where the specification allows conversion to a function pointer. Therefore, if recent versions of GCC do allow conversion to function pointers for [=], that not in accord with the specification.
Only captureless lambdas are convertible to function pointers; while f technically does not capture anything, it does have a default capture mode of capturing by value (for no apparent reason).
Change [=] to [] in the declaration of f and it should work as expected.
EDIT: The fact that this compiles with more recent versions of GCC (as noted by Kerrek) gives a strong indication that this is merely a compiler bug in the version you're using.
Why my VS2010 can't compile this code:
#include <functional>
#include <vector>
int main()
{
std::vector<int> vec;
std::bind(&std::vector<int>::push_back, std::ref(vec), 1)();
return 0;
}
You should be more specific why this doesn't seem to work for you.
#include <iostream>
#include <tr1/functional>
#include <vector>
int main(int argc, char* argv[]) {
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), 1)();
std::cout << "vec.size = " << vec.size() << std::endl;
std::cout << "vec[0] = " << vec[0] << std::endl;
return 0;
}
$ gcc -o test -lstdc++ test.cpp && ./test
vec.size = 1
vec[0] = 1
Update: Luc Danton is right, the issue here is the overloaded push_back. See question Are there boost::bind issues with VS2010 ?. Also, note that the issue is not limited to push_back, see Visual Studio 2010 and boost::bind.
The bottom line is that what you're trying to do isn't possible in portable C++. std::vector<>::push_back is guaranteed to be overloaded in C++11 compilers, as at a minimum there must be an overload for lvalues and an overload for rvalues.
Usually, when taking the address of an overloaded member function, §13.4/1 in the C++11 FDIS tells us that we can control which overload we're taking the address of thusly:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [ Note: That is, the class of which the function is a member is ignored when matching a pointer-to-member-function type. —end note ] The target can be
an object or reference being initialized,
the left side of an assignment,
a parameter of a function,
a parameter of a user-defined operator,
the return value of a function, operator function, or conversion,
an explicit type conversion, or
a non-type template-parameter.
The overloaded function name can be preceded by the & operator. An overloaded function name shall not be used without arguments in contexts other than those listed. [ Note: Any redundant set of parentheses surrounding the overloaded function name is ignored. —end note ]
The problem comes from §17.6.5.5/2:
An implementation may declare additional non-virtual member function signatures within a class by adding arguments with default values to a member function signature; hence, the address of a member function of a class in the C++ standard library has an unspecified type.
Consequently, it is not portable to ever take the address of a standard library class member function, as the type of such an expression is by definition unknowable except on an implementation-by-implementation basis.
Luc Danton's proposed workaround (specifically, using a lambda) is also what I would recommend:
std::vector<int> vec;
[&](){ vec.push_back(1); }();
Try this:
struct push_back {
void
operator()(std::vector<int>& vector, int i) const
{
vector.push_back(i);
}
};
// somewhere else:
std::vector<int> vec;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
With C++03 note that push_back cannot be a local type; with C++11 it can but it would be more idiomatic (and completely equivalent) to use a lambda.
In all likeliness your implementation provides overloads for std::vector<T>::push_back and thus its address would have to be disambiguated. If this is what happened, your compiler should have provided you with an appropriate error message. In all cases, you should explain what you mean by "it's not possible".
The point is not to use such helper
functions. – magenta
Then why didn't you put it in the question? I can't read your mind.
You can also try this:
std::vector<int> vec;
void (std::vector<int>::*push_back)(int const&) = &std::vector<int>::push_back;
std::tr1::bind(push_back(), std::tr1::ref(vec), 1)();
Which I believe is not guaranteed to success.
It should propably lok like this:
std::vector<int> vec;
std::tr1::bind(&std::vector<int>::push_back, std::tr1::ref(vec), _1)(1);
I want to declare type definition for a member function signature. Global function typedefs look like this:
typedef int (function_signature)(int, int);
typedef int (*function_pointer) (int, int);
But I'm not able to the same thing for a member function:
typedef int (foo::memberf_signature)(int, int); // memberf_pointer is not a member of foo
typedef int (foo::*memberf_pointer)(int, int);
It sounds logically to me, because foo:: is the syntax to access a member in the class foo.
How can I typedef just the signature?
For questions regarding the awkward function pointer syntax, I personally use a cheat-sheet: The Function Pointers Tutorial (downloadable here, thanks to Vector for pointing it out).
The signature of a member function, however, is a bit different from the signature of a regular function, as you experienced.
As you probably know, a member function has a hidden parameter, this, whose type need be specified.
// C++11 and above.
using Member = int (Foo::*)(int, int);
// C++03 and below.
typedef int (Foo::*Member)(int, int);
does let you specify that the first element passed to the function will be a Foo* (and thus your method really takes 3 arguments, when you think of it, not just 2.
However there is another reason too, for forcing you to specify the type.
A function pointer might refer to a virtual function, in which case things can get quite complicated. Therefore, the very size of the in-memory representation changes depending on the type of function. Indeed, on Visual Studio, a function pointer's size might vary between 1 and 4 times the size of a regular pointer. This depends on whether the function is virtual, notably.
Therefore, the class the function refers to is part of the signature, and there is no work-around.
You can factor out the target class in modern C++ (post 11) by utilizing the 'typedefing' qualities of template aliases. What you need would look like like:
template<typename T>
using memberf_pointer = int (T::*)(int, int);
Yet at the point of declaration, a pointer to member function utilizing this syntax would need to specify the target class:
// D is a member function taking (int, int) and returning int
memberf_pointer<foo> mp = &foo::D;
The reason it doesn't work with your current syntax is that operator precedence dictates that you're referring to a function named foo::memberf_signature, not any sort of type.
I don't know for sure if you can do this or not, but I couldn't come up with any combination of parenthese that induced the code to compile with g++ 4.2.
It works for me:
#include <iostream>
class foo
{
public:
int g (int x, int y) { return x + y ; }
} ;
typedef int (foo::*memberf_pointer)(int, int);
int main()
{
foo f ;
memberf_pointer mp = &foo::g ;
std::cout << (f.*mp) (5, 8) << std::endl ;
}
Well basically it can't work (at least I know no way using g++);
Using borland c++ compiler there would be the __closure keyword.
The reason why it does not compile is, that sizeof the functionpointer (on a x86 machine) occupies always <<32bits>>; but if you want to point to a class (interface) signature, the sizeof has to be 64bit: 32 bit for the this pointer (as the class interface is in the memory only once) and 32 bit for the actual function
But the __closure keyword is a bcb language 'hack' not standardized...
Is it posible to use the type of a prefiously declared function as a function pointer without using a typedef?
function declaration:
int myfunc(float);
use the function declaration by some syntax as function pointer
myfunc* ptrWithSameTypeAsMyFunc = 0;
Not as per the 2003 standard. Yes, with the upcoming C++0x standard and MSVC 2010 and g++ 4.5:
decltype(myfunc)* ptrWithSameTypeAsMyFunc = 0;
Yes, it is possible to declare a function pointer without a typedef, but no it is not possible to use the name of a function to do that.
The typedef is usually used because the syntax for declaring a function pointer is a bit baroque. However, the typedef is not required. You can write:
int (*ptr)(float);
to declare ptr as a function pointer to a function taking float and returning int -- no typedef is involved. But again, there is no syntax that will allow you to use the name myfunc to do this.
Is it posible to use the type of a prefiously declared function as a function pointer without using a typedef?
I'm going to cheat a bit
template<typename T>
void f(T *f) {
T* ptrWithSameTypeAsMyFunc = 0;
}
f(&myfunc);
Of course, this is not completely without pitfalls: It uses the function, so it must be defined, whereas such things as decltype do not use the function and do not require the function to be defined.
No, not at the present time. C++0x will change the meaning of auto, and add a new keyword decltype that lets you do things like this. If you're using gcc/g++, you might also look into using its typeof operator, which is quite similar (has a subtle difference when dealing with references).
No, not without C++0x decltype:
int myfunc(float)
{
return 0;
}
int main ()
{
decltype (myfunc) * ptr = myfunc;
}
gcc has typeof as an extension for C (don't know about C++) ( http://gcc.gnu.org/onlinedocs/gcc/Typeof.html ).
int myfunc(float);
int main(void) {
typeof(myfunc) *ptrWithSameTypeAsMyFunc;
ptrWithSameTypeAsMyFunc = NULL;
return 0;
}
int (*ptrWithSameTypeAsMyFunc)(float) = 0;
See here for more info on the basics.