I'm want to mimic std::function template arguments but I don't know how it really works.
Consider this code for example:
std::function<int(int)> p;
How do I write class template that mimics this template parameter <int(int)> ?
template<typename ...> <-- what should be here instead of `...`
MyClass
What I'm really trying to achieve is that I want to be able to typedef <int(int)> as function pointer and I want it to be generic not only for int (*func)(int) functions.
I'm trying to achieve something like this:
SomeSmartStruct<MyClass, int(int)>::MemFuncPointerType pMemFunc;
I want MemFuncPointerType to be of the following type:
int (__thiscall MyClass::* )(int)
And:
SomeSmartStruct<MyClass, int(int)>::FunctionPointer pFunc;
should be of this type:
int (__cdecl *)(int)
I'm using VS2010 so not all C++11 features are supported but it does implements std::function.
With variadic templates:
template <typename C, typename T>
struct make_member_function_pointer;
template <typename C, typename R, typename... Args>
struct make_member_function_pointer<C,R(Args...)>
{
using type = R(C::*)(Args...);
};
DEMO 1
Without variadic templates:
template <typename T> struct identity { typedef T type; };
template <typename C, typename T>
struct make_member_function_pointer;
template <typename C, typename R, typename Arg1>
struct make_member_function_pointer<C,R(Arg1)> : identity<R(C::*)(Arg1)> {};
template <typename C, typename R, typename Arg1, typename Arg2>
struct make_member_function_pointer<C,R(Arg1,Arg2)> : identity<R(C::*)(Arg1,Arg2)> {};
template <typename C, typename R, typename Arg1, typename Arg2, typename Arg3>
struct make_member_function_pointer<C,R(Arg1,Arg2,Arg3)> : identity<R(C::*)(Arg1,Arg2,Arg3)> {};
DEMO 2
Usage:
template <typename T, typename F>
struct SomeSmartStruct
{
typedef typename make_member_function_pointer<T,F>::type MemFuncPointerType;
typedef F* FunctionPointer;
};
Tests:
struct MyClass
{
int foo(int) {return 0;}
};
int bar(int) {return 0;}
int main()
{
SomeSmartStruct<MyClass, int(int)>::MemFuncPointerType pMemFunc = &MyClass::foo;
SomeSmartStruct<MyClass, int(int)>::FunctionPointer pFunc = &bar;
}
UPDATE
Can I somehow utilize the preprocessor to auto generate partial specializations of make_member_function_pointer? I've seen something similar is done using BOOST_PP_ITERATION but I don't know how it works.
Sure:
#include <boost/preprocessor.hpp>
template <typename T> struct identity { typedef T type; };
template <typename C, typename T>
struct make_member_function_pointer;
#define BOOST_PP_LOCAL_MACRO(n)\
template <typename C, typename R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Arg)>\
struct make_member_function_pointer<C,R(BOOST_PP_ENUM_PARAMS(n, Arg))> : identity<R(C::*)(BOOST_PP_ENUM_PARAMS(n, Arg))> {};
#define BOOST_PP_LOCAL_LIMITS (0, 20) // 20 is the limit of params
#include BOOST_PP_LOCAL_ITERATE()
Tests:
int bar10(int,int,int,int,int,int,int,int,int,int) {return 0;}
SomeSmartStruct<MyClass, int(int,int,int,int,int,int,int,int,int,int)>::FunctionPointer pFunc10 = &bar10;
DEMO 3
int(int) is just a type so can be matched by template <typename T>.
Surely too generic:
template<typename T>
struct Pointer
{
typedef T* type;
};
And then you may do
int foo(int i) {return i;}
int main() {
Pointer<int(int)>::type f = &foo;
}
Related
basically how to make following code compile?
I know it failed because compiler was trying to evaluate something like ([](int &i){})(0) but how to solve the problem?
template <class TElement>
struct foo {
TElement _e;
foo(TElement e) : _e(e){}
template <class Lambda>
void bar(Lambda f) {
using TResult = decltype(std::declval<Lambda>()(std::declval<TElement>()));
}
};
int main() {
foo<int>(0).bar([](int i){}); // compile
foo<int>(0).bar([](int &&i){}); // compile
foo<int>(0).bar([](int const &i){}); // compile
foo<int>(0).bar([](int &i){}); // failed
}
You may use following traits:
template <typename T>
struct return_type : return_type<decltype(&T::operator())>
{};
// For generic types, directly use the result of the signature of its 'operator()'
template <typename ClassType, typename ReturnType, typename... Args>
struct return_type<ReturnType(ClassType::*)(Args...) const>
{
using type = ReturnType;
};
Two ways. First:
using TResult = decltype(f(_e));
or second:
using TResult = typename std::result_of<Lambda&(TElement&)>::type;
Your code implicity says that the TElement is a temprary/rvalue. The & above makes them lvalues.
You might resolve it with:
template <typename Lambda, typename T>
struct lambda_return_type {
private:
template<typename U>
static constexpr auto check(U*) -> decltype(std::declval<Lambda>()(std::declval<U>()));
template<typename U>
static constexpr auto check(...) -> decltype(std::declval<Lambda>()(std::declval<U&>()));
public:
typedef decltype(check<T>(nullptr)) type;
};
and
void bar(Lambda f) {
typedef typename lambda_return_type<Lambda, TElement>::type TResult;
}
Is anyone knows how to declare generalized template form for the next template specialization:
template <template <class> class Container,
class Value,
class Return,
Return (Container<Value>::*Apply)(const Value &)>
class Example<Container<Value>, Apply>
{
};
Apply must be a pointer to a member function whoes signature is unknown in template declaration.
Do you mean something like this?
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
As an example:
template<typename... U>
struct T {
int f(int, char) { return 42; }
};
template<typename T, typename F>
struct S;
template<template <typename...> class C, typename R, typename... A>
struct S<C<A...>, R(A...)> {
using Apply = R(C<A...>::*)(A...);
// ...
};
int main() {
S<T<int, char>, int(int, char)>::Apply apply = &T<int, char>::f;
}
Pretty ugly, indeed, but that's what the OP (maybe) asked.
I'm looking to extend the functionality described here but for member functions, what would be the syntax in this case?
Also, the (*) in the template definition, is that de-referencing the function pointer so the compiler can deduce the template arguments?
Would appreciate any input!
Thanks
template <class F> struct ArgType;
template <class R, class T>
struct ArgType<R(*)(T)> {
typedef T type;
};
void f(int) {}
#include <type_traits>
#include <iostream>
int main() {
// To prove
std::cout << std::is_same< ArgType<decltype(&f)>::type, int >::value << '\n';
// To use
ArgType<decltype(&f)>::type a;
}
Pointer-to-members look like Ret (Cls::*)(Args...) [cv-qualifiers] [ref-qualifiers]. So you can extend your class to deduce the first type thusly:
template <class F> struct ArgType;
template <typename Ret, typename Cls, typename T, typename... Args>
struct ArgType<Ret (Cls::*)(T, Args...)> {
using type = T;
};
Note that you can make this more generic by write a metafunction that gives you the nth argument:
template <typename Ret, typename Cls, typename... Args>
struct ArgType<Ret (Cls::*)(Args...)> {
template <size_t N>
struct get_arg {
using type = typename std::tuple_element<N,
std::tuple<Args...>>::type;
};
};
So ArgType<F>::arg<0>::type would be the type you seek.
Given a C++11 function:
X f(A, B, C);
Is there anyway from within this function:
template<typename T>
void g(T t)
{
...
}
Called as follows:
g(f);
to determine:
the number of parameters of f
the type of parameter i of f
the return type of f
...
template<typename F>
void g(F f)
{
constexpr size_t n = num_params<F>::n; // 3
return_type<F>::type x; // X
tuple<param_types<F>::type...> a; // tuple<A, B, C>
}
?
Sure:
template <typename R, typename ...Args>
void g(R(&f)(Args...))
{
typedef R return_type;
unsigned int const n_args = sizeof...(Args);
// ...
}
Usage:
int foo(char, bool);
g(foo);
Something I had worked on that does what you want I think -- it is however limited to functors that define at most one function call operator (lambdas fit this restriction). It also works on MSVC 2012 CTP.
namespace detail {
////////////////////////////////////////////////////////////////////////////
//! Select between function pointer types
////////////////////////////////////////////////////////////////////////////
template <typename T>
struct callable_helper_ptr;
//! non-member functions
template <typename R, typename... Args>
struct callable_helper_ptr<R (*)(Args...)> {
typedef void object_t;
typedef R result_t;
typedef std::tuple<Args...> args_t;
};
//! member functions
template <typename R, typename O, typename... Args>
struct callable_helper_ptr<R (O::*)(Args...)> {
typedef O object_t;
typedef R result_t;
typedef std::tuple<Args...> args_t;
};
//! const member functions
template <typename R, typename O, typename... Args>
struct callable_helper_ptr<R (O::*)(Args...) const> {
typedef O object_t;
typedef R result_t;
typedef std::tuple<Args...> args_t;
};
////////////////////////////////////////////////////////////////////////////
//! Select between function pointers and functors
////////////////////////////////////////////////////////////////////////////
template <typename T, typename is_ptr = typename std::is_pointer<T>::type>
struct callable_helper;
//! specialization for functors (and lambdas)
template <typename T>
struct callable_helper<T, std::false_type> {
typedef callable_helper_ptr<decltype(&T::operator())> type;
};
//! specialization for function pointers
template <typename T>
struct callable_helper<T, std::true_type> {
typedef callable_helper_ptr<T> type;
};
} //namespace detail
////////////////////////////////////////////////////////////////////////////////
//! defines the various details of a callable object T
////////////////////////////////////////////////////////////////////////////////
template <typename T>
struct callable_traits {
typedef typename detail::callable_helper<T>::type::object_t object_t;
typedef typename detail::callable_helper<T>::type::result_t result_t;
typedef typename detail::callable_helper<T>::type::args_t args_t;
template <unsigned N>
struct arg : public std::tuple_element<N, args_t> {};
};
And my write up on the process behind writing if anyone is interested:
http://bkentel.wordpress.com/2012/12/12/defining-a-traits-type-for-callable-objects/
I am currently doing some template metaprogramming. In my case I can handle any "iteratable" type, i.e. any type for which a typedef foo const_iterator exists in the same manner. I was trying to use the new C++11 template metaprogramming for this, however I could not find a method to detect if a certain type is missing.
Because I also need to turn on/off other template specializations based on other characteristics, I am currently using a template with two parameters, and the second one gets produced via std::enable_if. Here is what I am currently doing:
template <typename T, typename Enable = void>
struct Foo{}; // default case is invalid
template <typename T>
struct Foo< T, typename std::enable_if<std::is_fundamental<T>::value>::type>{
void do_stuff(){ ... }
};
template<typename T>
struct exists{
static const bool value = true;
};
template<typename T>
struct Foo<T, typename std::enable_if<exists< typename T::const_iterator >::value >::type> {
void do_stuff(){ ... }
};
I was not able to do something like this without the exists helper template. For example simply doing
template<typename T>
struct Foo<T, typename T::const_iterator> {
void do_stuff(){ ... }
};
did not work, because in those cases where this specialization should be used, the invalid default case was instantiated instead.
However I could not find this exists anywhere in the new C++11 standard, which as far as I know simply is taking from boost::type_traits for this kind of stuff. However on the homepage for boost::type_traits does not show any reference to anything that could be used instead.
Is this functionality missing, or did I overlook some other obvious way to achieve the desired behavior?
If you simply want if a given type contains const_iterator then following is a simplified version of your code:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct Foo {};
template<typename T>
struct Foo <T, typename void_<typename T::const_iterator>::type> {
void do_stuff(){ ... }
};
See this answer for some explanation of how this technique works.
You can create a trait has_const_iterator that provides a boolean value and use that in the specialization.
Something like this might do it:
template <typename T>
struct has_const_iterator {
private:
template <typename T1>
static typename T1::const_iterator test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
And then you can specialize like this:
template <typename T,
bool IsFundamental = std::is_fundamental<T>::value,
bool HasConstIterator = has_const_iterator<T>::value>
struct Foo; // default case is invalid, so no definition!
template <typename T>
struct Foo< T, true, false>{
void do_stuff(){// bla }
};
template<typename T>
struct Foo<T, false, true> {
void do_stuff(){//bla}
};
Here's another version of a member type trait check:
template<typename T>
struct has_const_iterator
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::const_iterator*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
There is a couple of ways to do this. In C++03, you could use boost and enable_if to define the trait (docs, source):
BOOST_MPL_HAS_XXX_TRAIT_DEF(const_iterator);
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, typename boost::enable_if<boost::is_fundamental<T> >::type>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, typename boost::enable_if<has_const_iterator<T> >::type> {
void do_stuff(){ ... }
};
In C++11, you could use Tick like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator>
>;
};
template <typename T, typename Enable = void>
struct Foo;
template <typename T>
struct Foo< T, TICK_CLASS_REQUIRES(std::is_fundamental<T>::value)>{
void do_stuff(){ ... }
};
template<typename T>
struct Foo<T, TICK_CLASS_REQUIRES(has_const_iterator<T>())> {
void do_stuff(){ ... }
};
Also with Tick you can further enhance the trait to actually detect that the const_iterator is actually an iterator, as well. So say we define a simple is_iterator trait like this:
TICK_TRAIT(is_iterator,
std::is_copy_constructible<_>)
{
template<class I>
auto require(I&& i) -> valid<
decltype(*i),
decltype(++i)
>;
};
We can then define has_const_iterator trait to check that the const_iterator type matches the is_iterator trait like this:
TICK_TRAIT(has_const_iterator)
{
template<class T>
auto require(const T&) -> valid<
has_type<typename T::const_iterator, is_iterator<_>>
>;
};