Following my previous question, I found a problem with C++11 too, considering
typedef struct
{
int f_1;
float f_2;
} *Tptr;
this definition of a pointer to an anonymous struct named Tptr, doesn't generates a valid default constructor for the struct that Tptr it's supposed to point to.
This can be verified using the following code
#include <iostream>
typedef struct
{
int f_1;
float f_2;
} *Tptr;
int main()
{
...
Tptr k = NULL;
// trying to initialize a with a copy
decltype(*k) a = decltype (*k)();
// or with an ambiguos call
decltype(*k) a(decltype (*k)());
...
}
Conceptually the decltype(*k) works, thanks to the fact that k is statically declared ( and the resulting type is something like a reference to T, T&, not really a plain T ) .
As I understand what is going on the real problem is that there is no constructor for the pointed struct and I'm wondering why the compiler doesn't create the default special functions for this struct . The compiler has all the information that it needs to build an object that will replicate the required structure in such a way that an instance of Tptr will be able to point to a valid object, so why the compiler doesn't do that ?
The real problem has nothing to do with the lack of a constructor.
decltype(*k) a = decltype (*k)();
This is invalid because decltype (*k) is a reference to your anonymous struct, not your anonymous struct. If you want to get your anonymous struct, you can use std::remove_reference<...>::type:
std::remove_reference<decltype(*k)>::type a = std::remove_reference<decltype(*k)>::type();
decltype(*k) a(decltype (*k)());
This is valid but does not do what you want. This declares a as a function, returning decltype(*k), and taking decltype (*k)() as its parameter. You would need extra parentheses to let it be interpreted the way you want:
decltype(*k) a((decltype (*k)()));
but now you get the same problem as with your first attempt, and you could solve it the same way.
(Of course, in real code, I hope you simply give your struct a name.)
Related
I wonder why the language allows declaring a pointer to a member function/data although that member type doesn't exist and as we know that at compile-time, the static type must be know and the type must be full type before usage of that type apart from using an incomplete type in so restricted situations.
Here is my example:
struct Foo{
int bar(bool, bool){std::cout << "Foo::bar\n"; return x_;}
int x_ = 10;
void do_it()const{cout << "do_it()\n";}
void do_it(int, bool)const{cout << "do_it(int, bool)\n";};
};
int main(){
int (Foo::* pMemBar)(bool, bool) = &Foo::bar; // ok
(Foo{}.*pMemBar)(0, 0); // ok
int Foo::*pMemX = &Foo::x_;
std::cout << Foo{}.*pMemX << '\n';
std::string (Foo::* pMemFn)(char)const; // why this is allowed?
std::string Foo::* pMemDt = nullptr; // why allowed
}
As you can see everything is OK until the declaration of pointer pMemFn, that pointer is a pointer to a member function of class Foo that is const and takes a single argument aschar and returns an std::string. But there is no such version in the class Foo and as we know the compiler do knows all the members of a class so why it allows that? I know this pointer is not yet de-referenced thus there is no object of that class in such declaration and the compiler complains only when de-referencing it using a object of that type class Foo but why the compiler allows such declaration?
I think it would be more suitable for the compiler to refuse such declarations at the first place as it do for the static type of a pointer to a base class. What do you think? And is there a philosophy behind allowing that? Thank you!
Well first of all, you are allowed to declare pointer-to-member of class X before class X is defined (i.e., only a forward declaration of X has been seen). So in those cases, the compiler isn't yet able to determine that there exists no member of X with the appropriate type.
Beyond that, there are reasons why such pointer-to-member types are needed despite the fact that there is no actual member of that type. First, static_cast can be done both up and down the class hierarchy: in other words, let's say we have
struct Bar : Foo {
std::string s;
};
Now, an implicit conversion always exists from T Foo::* to T Bar::* since this is a safe conversion: if a T Foo::* value denotes a particular member of Foo, then any Bar object has such a member as well. When you use static_cast, it is possible to go the other way around: converting from T Bar::* to T Foo::*. You might wonder why one would ever want to do this. Well, it's not terribly common, but the idea is that just like how Foo* can point to any object derived from Foo (thus providing a common type with which to refer to such objects, enabling runtime polymorphism), T Foo::* also can point to any member of type T of any class derived from Foo. But you have to exercise caution, since using such a pointer requires knowledge that the member it denotes actually exists in the object pointed to.
Anyway, while (again) it's not terribly common, the point is that the compiler can't reject a std::string Foo::* because, for all it knows, there might be a class derived from Foo (possibly in another translation unit) that actually contains a std::string member.
Also, it's possible to reinterpret_cast between pointers to members of unrelated classes and unrelated member types. The rule is that T X::* can always be cast to U Y::* as long as T and U are both object types or both function types, except that you can't cast away constness this way (but you can do so with an additional const_cast). So I can do this for example:
struct Unused {};
using ObjType = int;
using FuncType = void();
And I can use ObjType Unused::* to hold pointers to any object type of any class; and I can use FuncType Unused::* to hold pointers to any function type of any class. But such pointers must be cast back to their original types before they can be used.
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);
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...
Based on other my question.
Consider the following code
template<typename T, int N>
struct A {
typedef T value_type; // save T to value_type
static const int size = N; // save N to size
};
Look, I can use value_type and size as template parameter.
typedef A<int, 2> A1;
typedef A<A1::value_type, A1::size + 3> A2; // OK, A2 is A<int,5>
Now I want to do the same with pointer to member:
struct Foo {
int m;
int r;
};
template<int Foo::*Mem>
struct B {
static int Foo::* const mp;
};
template<int Foo::*Mem>
int Foo::* const B<Mem>::mp = Mem; // Save pointer to member
But I get error.
typedef B<&Foo::m> B1;
typedef B<B1::mp> B2; // DOES NOT WORK
How to make last line to work?
Or how to get similiary result?
Note. I know that it does not work. No links to C++ Standard is needed.
I need workaround.
It shouldn't work according to C++ Standard 5.19/2:
Other expressions are considered constant-expressions only for the purpose of non-local static object initialization (3.6.2). Such constant expressions shall evaluate to one of the following:
— a null pointer value (4.10),
— a null member pointer value (4.11),
— an arithmetic constant expression,
— an address constant expression,
— a reference constant expression,
— an address constant expression for a complete object type, plus or minus an integral constant expression,
or
— a pointer to member constant expression.
It is not the answer to the original question, but it is the answer to this wrong statement.
Mike is right that it should compile. This is a bug in VS.
Not totally an answer but do accessing Mem directly work?
ie: B1::Mem instead of B1::mp.
I'm pretty sure the standard do not allow it since we normally typedef template name when it's a type instead of accessing it directly, but technically it could maybe allow it (not sure what would be the implication). Where your solution is probably sure not to work since it require initialisation of a static member that is done at runtime (correct me if I'm wrong), so it cannot be accessed at compile time like you want to do.
Maybe you could try giving us the bigger picture of what you're trying to do with your trait/policy class to see if a suitable workaround is possible.
I was surprised to find that there is not such thing. At least in the expected places, for example:
There is nothing here http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/index.html
nor near here http://en.cppreference.com/w/cpp/types/is_member_pointer
Based on this http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html and this http://en.cppreference.com/w/cpp/types/is_member_pointer it is not hard to roll your own.
#include<type_traits> // std::is_pointer_member
template<class MP> struct member_pointer_traits_helper;
template< class T, class U >
struct member_pointer_traits_helper<T U::*>{
using class_type = U;
using declaration_type = T;
};
template< class MP >
struct member_pointer_traits :
member_pointer_traits_helper<typename std::remove_cv<MP>::type> {};
struct B{
int b;
};
int main(){
using std::same;
static_assert(std::is_member_pointer<int B::*>::value == true, "");
static_assert(is_same<member_pointer_traits<int B::*>::class_type, B>{}, "");
static_assert(is_same<member_pointer_traits<int B::*>::declaration_type, int>{}, "");
static_assert(is_same<member_pointer_traits<decltype(&B::b)>::declaration_type, int>{}, "");
// static_assert(is_same<member_pointer_traits<double>::class_type, B>{}, ""); // error
}
I am not sure if the names are optimal.
Also when applied to non member pointer this will give a compiler error (this design is copied from http://www.boost.org/doc/libs/1_60_0/libs/type_traits/doc/html/boost_typetraits/reference/function_traits.html), another alternative could be to return the void type (which is obviously a failure return because void cannot be a class or a member type.)
(with some small modifications it can be used with C++98, used C++11 to make it more clear.)
For example:
struct test
{};
void thing(test())
{}
int main()
{
thing(test());
}
This code would give me error; however, the next example won't give me error:
void thing(int())
{}
int main()
{
thing(int());
}
My main question is, why the first example isn't possible and the second one is? Ultimately, both test and int are types, so I can't think why declaring an anonymous object of test in the thing function argument list isn't possible whereas declaring an anonymous object of type int in the thing function argument list is.
It is possible; it's just that you're doing it wrong.
Here is a declaration of a function taking an unnamed parameter of type test:
void thing(test);
Here is a declaration of a function taking an unnamed parameter of type pointer-to-function-returning-test:
void thing(test());
You want the former, not the latter.
That your second code example works is actually a magical oddity, stemming from the fact that int() is 0 is a valid null pointer constant, which may be used to initialise a function pointer; the example breaks as soon as you swap int() for some other integer, or if you run the code in a completely compliant C++14 compiler (because C++14 made it so that 0 but not int() is a valid null pointer constant).