I'm trying to create a class template that identifies functions, in which I can identify when a function is specializing the class model for R (*) (), but in std::function you can declare return_type (), and std::is_same< int(), int (*) () >.::value is zero.What does this int () statement mean and what is the difference between int () and int (*) ()?Updated: So int () is function declaration or function type and int (*)() is pointer to function.But waht is the type function of int (std::string::)()?It's something like int std::string::(), or like in std::function int(const std::string&)?How i can make this program output 1?
#include <iostream>
template<typename A,typename B>
struct IsSame{
enum{
value = 0};
};
template<typename A>
struct IsSame<A,A>{
enum{
value = 1
};
};
typedef int (SumType)(int,int)const;
class X{
public:
SumType sum;
};
int X::sum(int a,int b)const{
return a+b;
}
int main()
{
std::cout << IsSame< int (const std::string&,int,int)const,
decltype( &X::sum)>::value;
}
A function has a type like void() and if you take the address of that you get a pointer to that function void(*)(). They are not the same type, although a function can decay to a pointer to a function in a similar way that arrays decay to pointers to the first member.
This means you can declare a function:
void f();
and assign it to a pointer to a function (of the same signature):
void (*p_to_f)() = f;
and the function decays to a pointer to a function.
This is why I think it can be difficult to understand the difference between void() and void(*)(), but they are distinct types, and that difference can be important in templates (where this decay doesn't necessarily occur).
One important example of when decay doesn't happen is when matching template specialisations. Consider what std::function does for example:
template <class>
class function;
template <class R, class ... Args>
class function<R(Args...)> { /* ... stuff ... */ };
The fact that the specialisation is on a function type is different than if it were specialised on a pointer-to-function type.
function<void(int,int)> f;//matches specialisation
function<void(*)(int,int)> g;//does not match specialisation
In response to the OP's comment (now deleted):
In order to also match pointers to functions you can do:
template <class R, class ... Args>
function<R(*)(Args...)> : function<R(Args...>{};
which essentially means you treat functions and pointers to functions the same. If you want to match as many functions as you can, you also have to consider member functions, const member functions and noexcept functions (as of C++17). If you want to be completely thorough, there's also &, &&, const &, const&&, volatile, etc... but I wouldn't worry about those unless they actually come up.
Related
I know there are similar questions on SO, but the usages there seem different to what I have. Here is my MRE:
#include <iostream>
#include <functional>
using namespace std;
void freeFunction() {}
struct Foo { void memberFunction() {} };
template<typename FunctionPtrT>
void foo(FunctionPtrT* f) { f(); }
template<typename InstanceT, typename FunctionPtrT>
void bar(InstanceT&& i, FunctionPtrT f) { std::mem_fn(f)(i); }
template<typename InstanceT, typename FunctionPtrT>
void baz(InstanceT&& i, FunctionPtrT* f) {}
int main() {
foo(&freeFunction); //Ok, obviously
bar(Foo(), &Foo::memberFunction); //Ok, how?!
// Error: candidate template ignored: could not match 'FunctionPtrT *' against 'void (Foo::*)()'
baz(Foo(), &Foo::memberFunction); //why?!
return 0;
}
Why is &Foo::memberFunction not resolving to a pointer? What is the type of f in bar? If it's not a pointer how am I able to pass it to std::mem_fun that is defined as template< class M, class T > /*unspecified*/ mem_fn(M T::* pm) noexcept;?
General suggestion for type investigations
I think the easiest way to answer questions like "what is the type of x in this context" is to put a static_assert(std::is_same_v<void, delctype(x)>); in that same context. The compiler will then tell you the static_assertion failed because void is not equal to the type of x, revealing what that type is.
is &Foo::memberFunction a pointer?
And there are variations of that.
For instance, if you truly want to know wheter &Foo::memberFunction is a pointer, then ask it this way:
static_assert(std::is_pointer_v<decltype(&Foo::memberFunction)>);
and the compiler will tell you something along the lines of
Static_assert failed due to requirement 'std::is_pointer_v<void (Foo::*)()>' [static_assert_requirement_failed]
so it just can't match against FunctionPtrT*.
As regards
What is the type of f in bar?
if you put
static_assert(std::is_same_v<void, decltype(f)>);
inside of bar, the compiler will tell you
Static_assert failed due to requirement 'std::is_same_v<void, void (Foo::*)()>'
meaning that the type of f is void(Foo::*)().
How does &Foo::memberFunction's type from a free function pointer?
Compare this with the error you get if you define
void f();
and assert
static_assert(std::is_same_v<void, decltype(f)>);
The compiiler will tell you
Static_assert failed due to requirement 'std::is_same_v<void, void (*)()>'
So the point is that void(*)(), a pointer to a free function from void to void, is different from void (Foo::*)(), a pointer member of Foo function from void to void.
How can I restrict a template to be instatiated only for member functions?
If you want your template to match only member functions, can go for
template<typename InstanceT, typename R, typename C>
void baz(InstanceT&& i, R C::* f) { }
or, if you want it to match any member function of Foo, you can clearly either change the order of the template parameters such that you can provide C manually
template<typename C, typename R, typename InstanceT>
void baz(InstanceT&& i, R C::* f) { }
which allows you to call baz<Foo>(/* args */);, or you can simply hardcode Foo in place of C:
template<typename R, typename InstanceT>
void baz(InstanceT&& i, R Foo::* f) { }
And what if I want to restrict the match to member function with a specific signature?
As you see, we already have a placeholder R, for the return type.
If we also wanted to have a placeholder for the arguments, we could go for this:
template<typename R, typename C, typename ...Args>
void baz(R (C::*f)(Args...));
Which will just match the same function as the previous example. I showed this just to make you see that, if you want to type the arguments out, you must put parenthesis around C::*f, or just C::*, if you want to omit the name (the lack of parenthesis is the typo in the comment under your question). Therefore, if you want to restrict the match to a specific signature, let's say void(), this is how you do it:
template<typename C>
void baz(void (C::*f)());
What is the type of f in bar?
The type of f in bar is void (Foo::*)() i.e., a pointer to a member function of class Foo that has no parameter and has the return type of void.
The reason baz(Foo(), &Foo::memberFunction); fails is that &Foo::memberFunction is a pointer to a member function is distinct from an ordinary pointer to some type.
In fact, member function pointers are not actually pointers. So the argument of type void (Foo::*)() cannot be passed to parameter FunctionPtrT* f.
I am trying to understand the difference between function types <void()> and function pointer types <void (*)()>
stl::function can point to functions through <void()>, but I seem to need to use <void (*)()> in my own template classes:
void f1() {
std::cout << "hi!\n";
}
template<class T> struct X
{
T t;
};
int main()
{
std::function<void()> f = f1; // stl handles this, and f is callable
f(); // OK
// X<void()> x; // compilation error - a member of a class template cannot aquire a function type
X<void (*)()> x2; // OK
x2.t = f1; // OK
x2.t(); // OK
return 0;
}
Are function types such as <void()> new to C++ 11, and introduced along with std::function?
I have seen some other questions regarding this, but have not found an explanation which is clear to me, and searching the web for C++ function type does not yield satisfactory results.
I would greatly appreciate any clear explanation or references to one.
Function types aren’t new to C++11 at all: the existed even in C. However, you cannot have objects of function types, i.e.,
template <typename T>
struct X {
T t;
};
X<void()> does_not_work;
X<void(*)()> works;
However, you can turn a function type into a pointer type:
template <typename T>
struct X {
T* t;
};
Upon using a function differently than calling it the function decays into a function pointer. Decaying a function into a pointer is equivalent to taking the function’s address.
Of course, what std::function<...> does is quite different anyway: it actually defines a function call operator. To do so it deckares a general template and specializes it for function types:
template <typename> class function;
template <typename R, typename... A>
class function<R(A...)> {
public:
R operator()(A...);
// ...
};
You can't store a function in a variable, you can only store a function pointer. What is slightly confusing is that the language automatically converts a function into a function pointer when you try to assign the function name to a variable.
Your class would have to be:
template<class T> struct X
{
T* t;
};
To make X<void()> x work. This would of course stop X<void (*)()> x2 from working, you'd have to specialise the template for different types.
I'm writing a C++ template that needs two params: typename T, and an arbitrary function that maps T to an unsigned int.
How can I declare and use a template that can do that? I'd like to keep it simple, so that any dumb function can be used.
UPDATE:
Here is an example of what I'd like to do:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
And, in this file:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
UPDATE upon writing code
Based on the answers, I tried writing code, but it won't compile. Or rather, the template will compile, but not the test which invokes it.
The template code looks like this:
template<typename T, typename f>
class C {
...f(T)...
...
The invocation code looks like:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
The error message is:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
It seems like it's trying to use S's constructor for some reason, as opposed to using the operator() which I want it to do.
The purpose of the f parameter is that the SortedContainer needs to be able to position T by an integer value. T is not necessarily an integer or even Comparable, so the caller, when instantiating a SortedContainer, needs to pass not only type T, but a function f to transform T to an integer.
The common way of doing this is to accept a general type F for the function. This will allow any kind of function-like object, whether it is a function pointer or a class object with an overloaded operator(). So:
template<class T, class F>
class SortedContainer {
// ...
}
Compare with things like std::map which does exactly this.
The disadvantage of this is that you cannot control what the prototype of the function is. This may or may not be a problem. One way is just to use it as if it was T-to-unsigned int and rely on the fact that the type system will catch any errors at the point of use.
Another way would be to verify the constraint with some kind of type trait. An example:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
Edit: I wrote a small example to convince myself i got the assert right, might as well post it. Here, using A will compile OK but B will fail the assertion.
#include <type_traits>
template<class T, class F>
class SortedContainer {
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
};
struct A {
unsigned int operator()(double) { return 0; }
};
struct B {
double operator()(double) { return 0; }
};
int main() {
SortedContainer<double, A> a;
SortedContainer<double, B> b;
}
Based on your other edit:
Note that the templated type F only captures the type of the function. You still need an object of this type - the actual function - to call. Again, compare with std::map which first is templated to take a comparator type, and then has a constructor that takes an object of this type. This is true even if you use a normal function - the type will be SortedContainer<T, unsigned int (*)(T)>, but you would somehow need to pass the actual function pointer into the container (probably through the constructor).
Something like this:
template<class T, class F>
class SortedContainer {
public:
SortedContainer(F f = F()): func(f) {}
void foo() {
// ...
func();
// ...
}
private:
F func;
};
struct A {
unsigned int operator()() { return 0; }
};
int main() {
A a;
SortedContainer<double, A> c(a);
c.foo();
}
IMO, you don't require a separate template argument for Function F.
template<typename T> // F not required!
class SortedContainer {
...
};
Choose a good name and use that function by overloading it for various cases. e.g. to_uint()
Since you want to map (i.e. relate) a type to an unsigned int (uint), use following function in global scope:
template<typename T>
uint to_uint (const T& t) {
return t.to_uint(); // Must have `uint to_uint() const` member, else error
}
// Overloads of `to_uint()` for PODs (if needed)
template<typename T> // For all kinds of pointers
uint to_uint (const T* const pT) {
if(pT == nullptr)
<error handling>;
return to_uint(*pT);
}
Scenario: For Sorted_Container<X>, whenever to_uint(x) is invoked, then:
If X is a class, then it must have uint to_uint() const method
Else if X is a POD, then you may have to overload to_uint() for that type
Else, the compiler will generate an error
It's as you said, pretty much:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
if you actually wanted the argument to be a function pointer rather than a function,
template< typename T, unsigned int (*f)(T) >
and similarly if you want the argument to be a function reference.
(naturally, this will only work for dumb functions, not for function objects with an operator() operator of the right signature)
You may use C-style function pointers as #Hurkyl suggests, or std::function which probably can't be template parameters, but I think that idea is wrong.
C++ templates are duck-typed, so STL code in many places (std::unordered_map -> std::hash, std::sort -> std::less) relies on that. I think you should also apply this approach - just ask user to provide specialization for type T:
/* Universal implementation */
template<typename T>
unsigned int sorted_container_weight(T t) { return t; }
template<typename T>
class SortedContainer {
T t;
public:
unsigned int somefunc() {
return sorted_container_weight(t);
}
};
template<>
unsigned int sorted_container_weight<Package>(Package p) { return p.w; }
SortedContainer<Package> sc;
Consider the code:
class Character
{
void kill();
void send_to_wall();
}
template <typename T>
void GeorgeFunc(T fp)
{
??? obj;
(obj.*fp)();
}
int main()
{
GeorgeFunc(&Character::kill);
}
So my question here is: how can I get ???? It seems that the compiler definitely knows what this type is (Character) during template instantiation, but I'm not sure how to get at it. My current workaround is to change to: void GeorgeFunc(void (T::*fp)()), but it would be cleaner to simply get the type from the member function pointer. decltype(fp) would return void(Character::*)(), and decltype(fp()) would return void. Any way to get Character?
Yes, just use a trait to determine this.
template <typename> struct member_function_traits;
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...)>
{
typedef Return return_type;
typedef Object instance_type;
typedef Object & instance_reference;
// Can mess with Args... if you need to, for example:
static constexpr size_t argument_count = sizeof...(Args);
};
// If you intend to support const member functions you need another specialization.
template <typename Return, typename Object, typename... Args>
struct member_function_traits<Return (Object::*)(Args...) const>
{
typedef Return return_type;
typedef Object instance_type;
typedef Object const & instance_reference;
// Can mess with Args... if you need to, for example:
static constexpr size_t argument_count = sizeof...(Args);
};
Now your declaration is:
typename member_function_traits<T>::instance_type obj;
However, I would argue that since you require a member function pointer (other types would fail to instantiate due to the line (obj.*fp)()1) that your function should take a member function pointer directly instead of a completely generic type.
So this definition would not only work, but I would consider it preferred -- the error messages when someone uses something other than a pointer-to-member-function will be much clearer because the argument type will be incompatible:
template <typename Return, typename Object>
void GeorgeFunc(Return (Object::*fp)())
{
Object obj;
(obj.*fp)();
}
Note that this does allow passing a pointer-to-member-function that returns any type. Since we don't really use the return value, we don't care what it is. There is no reason to enforce that it is void as in your "workaround."
The only downside to using this approach is that you need two overloads if you intend to also accept pointers to member functions that are declared const. The completely generic implementation does not have this limitation. (I've long wished that pointers to const member functions were implicitly convertible to pointers to non-const member functions, but this is currently not allowed by C++.)
1 This isn't 100% true. If you use a completely generic type as you are right now then the caller could theoretically pass a member data pointer instead of a member function pointer. obj.*fp would evaluate as a reference to the data member, and then you would be invoking operator()() on it. As long as the data member's type implemented this operator then the template function GeorgeFunc could be instantiated.
How can I call a may-existing member function by template technology, I am not want to use virtual method, because the class is arbitrary.
For example:
class A {
void setValue(int value);
};
How to define a template to call class A's setValue if it existing, else do nothing.
The template is something like:
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
It's about invoking, not checking.
You can take advantage of SFINAE to make a class template that checks for the existence of a member function in a given class, and use the result as a boolean flag to specialize your template for the case when there is no function, and the case when the member function exists:
template<typename T , bool member_exists = has_set_value<T>::result>
struct call_if_exist;
template <typename T>
struct call_if_exist<T,true> {
void invokeOrNot(T& a, int value){ // EXISTING: setValue
a.setValue(value);
}
}
template <typename T>
struct call_if_exist<T,false> {
void invokeOrNot(T& a, int value){ // NOT EXISTING: do nothing
}
}
Edit: The has_set_value trait
template<typename T>
class has_set_value
{
typedef struct{ char c[1]; } yes;
typedef struct{ char c[2]; } no;
template<typename U> static yes test(&U::set_value);
template<typename U> static no test(...);
public:
static const bool result = sizeof( test<T>(NULL) ) == sizeof( yes );
};
This class is the typical example of the usage of SFINAE to check for the existence of a member (type or function) of a certain class.
First we define two typedefs, yes and no, which are used to differentiate overload resolutions through the sizeof operator.
The first overload of test() has a pointer to the member function as parameter, and the last is an overload which goal is to be called by everything thats not a pointer to the member. This is done through a variadic-function (Note the ellipsis), which can be used with any kind of parameter.
The point of the implementation is even if the second overload can hold any parameter, the first is an explicit case for pointers to our member function. So if the parameter could be a pointer to the function, the call is resolved to the first function, else its resolved to the second.
As I said before, we use the typedefs to differentiate the overload resolution through the sizeof operator: Note that the first overload returns yes and the later returns no. So if the size of the result type of the call to test() using a pointer (NULL) is equal to the size of yes, means that the overload is resolved to the first, and the class passed as parameter (T) has a member function called set_value.
Alexandrescu's Modern C++ Dessign includes an example of this kind of trait in chapter two to check if one type is implicitly convertible to other.