I'm trying to extend to methods the technique explained here for functions. The problem is the method signature template parameter. For instance, a wrapper for the sin function is created this way:
template<typename Sig, Sig& S> struct wrapper;
template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
// blah
}
and then is instantiated with
wrapper<decltype(sin), sin>
But for a method bool Foo::blah(int) this technique is rejected:
template<class C, typename Sig, Sig& S> struct wrapper;
template<class C, typename Ret, typename... Args, Ret(C::*P)(Args...)>
struct wrapper<Ret(C::)(Args...), P> {
// blah
}
wrapper<decltype(Foo::blah), &Foo::blah>
So what's the proper syntax?
There is no analogue of free function types for member functions. You need to work with the pointers-to-member-functions directly.
Try something like this:
template <typename C, typename MFP, MFP> struct wrapper;
template <typename C, typename R, typename ...Args, R (C::*MFP)(Args...)>
struct wrapper<C, R (C::*)(Args...), MFP>
{
// ...
};
Note that this will get a bit verbose if you want to admit all the possible combinations of CV- and rvalue-qualifications.
Related
Suppose I have a class with the following signature:
template <typename T, typename... Args>
class A;
But how this class behaves should depend on some other parameter, let's say it's the value of T::value:
template <typename T, typename... Args, typename Enable>
class A;
template <typename T, typename... Args, typename = typename std::enable_if<T::value>::type>
class A
{
// do something
};
template <typename T, typename... Args, typename = typename std::enable_if<!T::value>::type>
class A
{
// do something else
};
int main() { return 0; }
However, this program gives the following error:
prog.cpp:6:11: error: parameter pack ‘Args’ must be at the end of the
template parameter list
class A;
I have struggled to find a good source of information on the use of enable_if to select classes with variadic templates. The only question I could find is this one:
How to use std::enable_if with variadic template
But despite the name, this question and its answers aren't much help. If someone could provide or link a guide on how this should be approached and why that would be appreciated.
First of all, what you're trying is writing multiple definitions of a class template. That's not allowed because it violates One definition rule. If you want to do conditional enabling with classes, you need specializations. Also, the compiler error message already told you, you can't have a variadic parameter pack in the middle of a parameter list.
One way to do it would be:
namespace detail {
template<typename T, typename Enable, typename... Args>
class A_impl;
template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<T::value>::type, Args...> {
// code here
};
template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<!T::value>::type, Args...> {
// code here
};
}
template<typename T, typename...Args>
class A : public detail::A_impl<T, void, Args...> {};
Jonathan's way is also perfectly fine if the condition is really a bool, but it might not be useful if you wish to add more specializations that each depend on several conditons.
It looks as though for your purposes you don't need to enable/disable the class, you just need a partial specialization:
template <typename T, bool B = T::value, typename... Args>
class A;
template <typename T, typename... Args>
class A<T, true, Args...>;
template <typename T, typename... Args>
class A<T, false, Args...>;
I'm doing some template metaprogramming involving function pointers. Because the function types for non-member and member function pointers are different, I'm trying to specialize between the two. Furthermore, I want the pointer to the function to be provided as a non-type template argument instead of a parameter to a function in the struct. So far here's what I have attempted:
template <typename T, T>
struct register_method;
template <typename R, typename... Args>
struct register_method<R(Args...), R (*method)(Args...)>
{
static R invoke(Args&&... params)
{
return (*method)(std::forward<Args>(params)...);
}
};
template <typename T, typename R, typename... Args>
struct register_method<R(Args...), R (T::*method)(Args...)>
{
static R invoke(T* instance, Args&&... params)
{
return (instance->*method)(std::forward<Args>(params)...);
}
};
However this fails to compile (here's just the first error):
prog.cc:14:48: error: 'Args' does not refer to a value
struct register_method<R(Args...), R (*method)(Args...)>
^
prog.cc:13:35: note: declared here
template <typename R, typename... Args>
^
I'm not really sure what it is trying to tell me. My goal is to utilize these objects like so:
void the_func(float val)
{
std::cout << "the_func called: " << val << "\n";
}
int main()
{
register_method<decltype(&the_func), &the_func>::invoke(50.f);
}
How can I get this working? If there's an opportunity to simplify, that would be great too (for example, if I can get away with just passing the function pointer to the template instead of also doing a decltype, which should reduce boilerplate.
EDIT: Also want to add that the reason I need separate specializations for non-member and member functions extend beyond just the function types being different. There is static state between the two that is different, due to the business rules I attach to the different function types. I have omitted those details here to keep the question simple.
Here's how you can fix the code:
template <typename T, T>
struct register_method;
template <typename R, typename... Args, R (*method)(Args...)>
struct register_method<R (*)(Args...), method>
{
template <typename ...P>
static R invoke(P &&... params)
{
return (*method)(std::forward<P>(params)...);
}
};
template <typename T, typename R, typename... Args, R (T::*method)(Args...)>
struct register_method<R (T::*)(Args...), method>
{
template <typename ...P>
static R invoke(T *instance, P &&... params)
{
return (instance->*method)(std::forward<P>(params)...);
}
};
Note that you have to introduce a separate parameter pack for the forwarding references to work, since they only work if the template parameter is being deduced.
And here is an alternative solution using C++17 auto template parameters:
template <auto method>
struct register_method;
template <typename R, typename... Args, R (*method)(Args...)>
struct register_method<method>
{
template <typename ...P>
static R invoke(P &&... params)
{
return (*method)(std::forward<P>(params)...);
}
};
template <typename T, typename R, typename... Args, R (T::*method)(Args...)>
struct register_method<method>
{
template <typename ...P>
static R invoke(T *instance, P &&... params)
{
return (instance->*method)(std::forward<P>(params)...);
}
};
Specialization should look like
template <typename T, T>
struct register_method;
template <typename R, typename... Args, R (*method)(Args...)>
struct register_method<R (*)(Args...), method>
{
static R invoke(Args... params)
{
return (*method)(std::forward<Args>(params)...);
}
};
template <typename C, typename R, typename... Args, C (T::*method)(Args...)>
struct register_method<R (C::*)(Args...), method>
{
static R invoke(T* instance, Args... params)
{
return (instance->*method)(std::forward<Args>(params)...);
}
};
Consider the following code:
template<typename>
struct S { };
template<typename, typename>
struct B;
template <typename R, typename... Args, template<class> class C>
struct B<R(Args...), C<R>> {
void f() { }
};
int main() {
B<void(), S<void>> b;
b.f();
}
It compiles and has no problem.
Anyway, whenever one decides to use B, it has to provide two types.
What I'd like to achieve is to default somehow the second parameter (I know, partial specializations do not accept a default for their parameters) and let an user define it's type as B<void()> instead of B<void(), S<void>>.
Unfortunately, because of template template, partial specialization and the dependency existent between the parameters, all together they lead to a puzzle against which I'm struggling since a couple of hours.
Is there any clever solution to do that?
So far, I have been able to solve it with intermediate structures, but I don't like it so much...
Partial specializations don't accept default parameters, but the primary does. You can just add it there:
template<typename Sig, typename X = S<return_type_t<Sig>>>
struct B;
Then all you need to do is implement a return type metafunction for a signature. Something like:
template <class Sig>
struct return_type;
template <class Sig>
using return_type_t = typename return_type<Sig>::type;
template <class R, class... Args>
struct return_type<R(Args...)> {
using type = R;
};
You may create an helper class for that:
template <typename T> struct default_arg;
template <typename R, typename... Args>
struct default_arg<R(Args...)>
{
using type = S<R>;
};
template<typename Sign, typename T = typename default_arg<Sign>::type>
struct B;
Demo
Here we change B into a template alias.
B_t does the default arg work.
B_impl is the implementation of B without any default args.
B is a using alias that gets the result of B_t.
template<class> struct S {};
template<class, class>
struct B_impl;
template<class R, class... Args, template<class...> class C>
struct B_impl<R(Args...), C<R>> {
void f() { }
};
template<class, class=void>
struct B_t;
template<class R, class...Args>
struct B_t<R(Args...), void>:
B_t<R(Args...),S<R>>
{};
template<class R, class... Args, template<class...> class C>
struct B_t<R(Args...), C<R>> {
using type=B_impl<R(Args...), C<R>>;
};
template<class Sig, class Z=void>
using B=typename B_t<Sig,Z>::type;
The downside is that pattern-matching on B won't work well.
Suppose I have a class with the following signature:
template <typename T, typename... Args>
class A;
But how this class behaves should depend on some other parameter, let's say it's the value of T::value:
template <typename T, typename... Args, typename Enable>
class A;
template <typename T, typename... Args, typename = typename std::enable_if<T::value>::type>
class A
{
// do something
};
template <typename T, typename... Args, typename = typename std::enable_if<!T::value>::type>
class A
{
// do something else
};
int main() { return 0; }
However, this program gives the following error:
prog.cpp:6:11: error: parameter pack ‘Args’ must be at the end of the
template parameter list
class A;
I have struggled to find a good source of information on the use of enable_if to select classes with variadic templates. The only question I could find is this one:
How to use std::enable_if with variadic template
But despite the name, this question and its answers aren't much help. If someone could provide or link a guide on how this should be approached and why that would be appreciated.
First of all, what you're trying is writing multiple definitions of a class template. That's not allowed because it violates One definition rule. If you want to do conditional enabling with classes, you need specializations. Also, the compiler error message already told you, you can't have a variadic parameter pack in the middle of a parameter list.
One way to do it would be:
namespace detail {
template<typename T, typename Enable, typename... Args>
class A_impl;
template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<T::value>::type, Args...> {
// code here
};
template<typename T, typename... Args>
class A_impl<T, typename std::enable_if<!T::value>::type, Args...> {
// code here
};
}
template<typename T, typename...Args>
class A : public detail::A_impl<T, void, Args...> {};
Jonathan's way is also perfectly fine if the condition is really a bool, but it might not be useful if you wish to add more specializations that each depend on several conditons.
It looks as though for your purposes you don't need to enable/disable the class, you just need a partial specialization:
template <typename T, bool B = T::value, typename... Args>
class A;
template <typename T, typename... Args>
class A<T, true, Args...>;
template <typename T, typename... Args>
class A<T, false, Args...>;
How can I deduce statically if an argument is a C++ function object (functor)?
template <typename F>
void test(F f) {}
I tried is_function<F>::value, but this doesn't work. It also seems there is no is_functor trait, so perhaps it's not possible. I appear to be only looking for a specific member function, in this case the function call operator: F::operator().
It is possible to create such a trait, with two restrictions:
For the compiler, a free function is something fundamentally different from a class functor that overloads operator(). Thus we have to treat both cases seperately when implementing. This is not a problem for usage though, we can hide this implementation detail from the user.
We need to know the signature of the function you want to call. This is usually not a problem, and it does have the nice side effect that our trait is able to handle overloads pretty natively.
Step one: Free functions
Let's start with free functions, because they are little easier to detect. Our task is, when given a function pointer, to determine whether the signature of that function pointer matches the signature passed as the second template argument. To be able to compare those, we either need to get a grasp of the underlying function signature, or create a function pointer of our signature. I arbitrarily chose the latter:
// build R (*)(Args...) from R (Args...)
// compile error if signature is not a valid function signature
template <typename, typename>
struct build_free_function;
template <typename F, typename R, typename ... Args>
struct build_free_function<F, R (Args...)>
{ using type = R (*)(Args...); };
Now all that's left to do is to compare and we are done with the free function part:
// determine whether a free function pointer F has signature S
template <typename F, typename S>
struct is_function_with_signature
{
// check whether F and the function pointer of S are of the same
// type
static bool constexpr value = std::is_same<
F, typename build_free_function<F, S>::type
>::value;
};
Step two: Class functors
This one is a little more involved. We could easily detect with SFINAE whether a class defines an operator():
template <typename T>
struct defines_functor_operator
{
typedef char (& yes)[1];
typedef char (& no)[2];
// we need a template here to enable SFINAE
template <typename U>
static yes deduce(char (*)[sizeof(&U::operator())]);
// fallback
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<T>(0)) == sizeof(yes);
};
but that does not tell us whether one exists for our desired function signature! Luckily, we can use a trick here: pointers are valid template parameters. Thus we can first use the member function pointer of our desired signature, and check whether &T::operator() is of that type:
template <typename T, T> struct check;
Now check<void (C::*)() const, &C::operator()> will only be a valid template instantiation if C does indeed have a void C::operator()() const. But to do this we first have to combine C and the signature to a member function pointer. As we already have seen, we need to worry about two extra cases we did not have to care about for free functions: const and volatile functions. Besides that it's pretty much the same:
// build R (C::*)(Args...) from R (Args...)
// R (C::*)(Args...) const from R (Args...) const
// R (C::*)(Args...) volatile from R (Args...) volatile
// compile error if signature is not a valid member function signature
template <typename, typename>
struct build_class_function;
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...)>
{ using type = R (C::*)(Args...); };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) const>
{ using type = R (C::*)(Args...) const; };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) volatile>
{ using type = R (C::*)(Args...) volatile; };
Putting that and our findings concerning the check helper struct together, we get our check metafunction for functor objects:
// determine whether a class C has an operator() with signature S
template <typename C, typename S>
struct is_functor_with_signature
{
typedef char (& yes)[1];
typedef char (& no)[2];
// helper struct to determine that C::operator() does indeed have
// the desired signature; &C::operator() is only of type
// R (C::*)(Args...) if this is true
template <typename T, T> struct check;
// T is needed to enable SFINAE
template <typename T> static yes deduce(check<
typename build_class_function<C, S>::type, &T::operator()> *);
// fallback if check helper could not be built
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
};
Step three: Putting the pieces together
We are almost done. Now we only need to decide when to use our free function, and when the class functor metafunctions. Luckily, C++11 provides us with a std::is_class trait that we can use for this. So all we have to do is specialize on a boolean parameter:
// C is a class, delegate to is_functor_with_signature
template <typename C, typename S, bool>
struct is_callable_impl
: std::integral_constant<
bool, is_functor_with_signature<C, S>::value
>
{};
// F is not a class, delegate to is_function_with_signature
template <typename F, typename S>
struct is_callable_impl<F, S, false>
: std::integral_constant<
bool, is_function_with_signature<F, S>::value
>
{};
So we can finally add the last piece of the puzzle, being our actual is_callable trait:
// Determine whether type Callable is callable with signature Signature.
// Compliant with functors, i.e. classes that declare operator(); and free
// function pointers: R (*)(Args...), but not R (Args...)!
template <typename Callable, typename Signature>
struct is_callable
: is_callable_impl<
Callable, Signature,
std::is_class<Callable>::value
>
{};
Now we clean up our code, put implementation details into anonymous namespaces so they are not acessible outside of our file, and have a nice is_callable.hpp to use in our project.
Full code
namespace // implementation detail
{
// build R (*)(Args...) from R (Args...)
// compile error if signature is not a valid function signature
template <typename, typename>
struct build_free_function;
template <typename F, typename R, typename ... Args>
struct build_free_function<F, R (Args...)>
{ using type = R (*)(Args...); };
// build R (C::*)(Args...) from R (Args...)
// R (C::*)(Args...) const from R (Args...) const
// R (C::*)(Args...) volatile from R (Args...) volatile
// compile error if signature is not a valid member function signature
template <typename, typename>
struct build_class_function;
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...)>
{ using type = R (C::*)(Args...); };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) const>
{ using type = R (C::*)(Args...) const; };
template <typename C, typename R, typename ... Args>
struct build_class_function<C, R (Args...) volatile>
{ using type = R (C::*)(Args...) volatile; };
// determine whether a class C has an operator() with signature S
template <typename C, typename S>
struct is_functor_with_signature
{
typedef char (& yes)[1];
typedef char (& no)[2];
// helper struct to determine that C::operator() does indeed have
// the desired signature; &C::operator() is only of type
// R (C::*)(Args...) if this is true
template <typename T, T> struct check;
// T is needed to enable SFINAE
template <typename T> static yes deduce(check<
typename build_class_function<C, S>::type, &T::operator()> *);
// fallback if check helper could not be built
template <typename> static no deduce(...);
static bool constexpr value = sizeof(deduce<C>(0)) == sizeof(yes);
};
// determine whether a free function pointer F has signature S
template <typename F, typename S>
struct is_function_with_signature
{
// check whether F and the function pointer of S are of the same
// type
static bool constexpr value = std::is_same<
F, typename build_free_function<F, S>::type
>::value;
};
// C is a class, delegate to is_functor_with_signature
template <typename C, typename S, bool>
struct is_callable_impl
: std::integral_constant<
bool, is_functor_with_signature<C, S>::value
>
{};
// F is not a class, delegate to is_function_with_signature
template <typename F, typename S>
struct is_callable_impl<F, S, false>
: std::integral_constant<
bool, is_function_with_signature<F, S>::value
>
{};
}
// Determine whether type Callable is callable with signature Signature.
// Compliant with functors, i.e. classes that declare operator(); and free
// function pointers: R (*)(Args...), but not R (Args...)!
template <typename Callable, typename Signature>
struct is_callable
: is_callable_impl<
Callable, Signature,
std::is_class<Callable>::value
>
{};
Ideone example with some tests
http://ideone.com/7PWdiv
Although this does not work for overloaded functions, for all other cases (free functions, classes implementing operator(), and lambdas) this short solutions works in C++11:
template <typename T, typename Signature>
struct is_callable: std::is_convertible<T,std::function<Signature>> { };
Note: std::is_invocable is available since C++17.
You can use the following concept in c++20
template<typename F>
concept FunctionObject = requires (F) {
&F::operator();
};
Is an is_functor C++ trait class possible?
Yes, it is possible to manually implement a validation for functors.
I tried is_function::value, but this doesn't work.
You are on the right path, it is possible to implement using std::function
Remember that std::function also accepts functions, function pointers and functor instances in its constructor.
Example:
struct Test {
public:
bool operator()(int){
return true;
}
};
void test(int){
}
void example(std::function<void(int)> ex){
cout << "Called" << endl;
};
int main()
{
example(test);
example(&test);
example(Test{});
}
That said, the logic that will be used to validate if a class has a function call overload operator (functor) is similar to the code above.
That is, if the std::function<void(int)> accepts an instance of the class Test{} means the class has a functor, otherwise it doesn't.
Example of an possible solution
Here is the source code:
//F: Test class
//Args...: The arguments, ex: int or none
template <typename F, typename... Args>
struct is_functor :
is_constructible <
function<void(Args ...)>, F
>
{};
Example usage:
is_functor<Test, int> -> True result
is_functor -> False result
Info about std::is_constructible
Is a trait class that identifies whether T is a constructible type with the set of argument types specified by Arg.
For this class, a constructible type is a type that can be constructed using a particular set of arguments.
is_constructible inherits from integral_constant as being either true_type or false_type, depending on whether T is constructible with the list of arguments Args.
In short, it checks if a given class has a constructor, for example:
struct Test2 {
Test(bool, int){}
};
std::is_constructible<Test2, bool, int> -> True result
std::is_constructible<Test2, float> -> False result
Example of implementation:
template <typename, typename, typename ...Args>
struct is_constructible_impl : false_type {};
template <typename T, typename ...Args>
struct is_constructible_impl <
void_t<decltype(T(std::declval<Args>()...))>, T, Args...
> : true_type {};
template <typename T, typename ...Args>
struct is_constructible : is_constructible_impl<void_t<>, T, Args...> {};
Final explanation
In the implementation of is_functor it was checked if std::function<void(int)> accepts an instance of Test{}, which is true.
References:
How is std::is_constructible<T, Args> implemented?
Can std::is_invocable be emulated within C++11?
https://replit.com/#LUCASP6/RowdyAlphanumericCode#main.cpp
template<typename T, typename Sign>
struct is_functor
{
typedef char yes[1];
typedef char no [2];
template <typename U, U> struct type_check;
template <typename _1> static yes &chk(type_check<Sign, &_1::operator()>*);
template <typename > static no &chk(...);
static bool const value = sizeof(chk<T>(nullptr)) == sizeof(yes);
};
Altered from this answer.
It could be used like...
template<typename T>
typename std::enable_if<is_functor<T, void(T::*)()>::value>::type func()
{
}