I would like to do the following:
template<typename Func>
class FunctionWrapper
{
public:
typedef decltype(Func()) ReturnType;
typedef ... ArgsType;
FunctionWrapper(Func func)
{
func_ = func;
}
ReturnType operator() (ArgsType args)
{
return func_(args);
}
private:
Func func_;
};
The problem is I don't know how to deduce the ArgsType from Func type. I'd like to make it work when the function returns/accepts nothing as well.
The usecase would then be:
FunctionWrapper<myFunction> wrapper;
auto result = wrapper(1, 2, 3);
You can determine the argument and return type(s) in operator() and use perfect forwarding:
template <typename Func>
class FunctionWrapper
{
Func func_;
public:
FunctionWrapper(Func func) : func_(func) {}
template <typename... Args>
auto operator() (Args&&... args)
-> decltype(func_(std::forward<Args>(args)...)) {
return func_(std::forward<Args>(args)...);
}
};
There is no generic way to do that, neither is it logical. Just think of the case when Func overloads operator() and accepts different argument types. You could, however, mandates that Func defines its argument type as a member type for utility like FunctionWrapper to access. See the possible member types of std::function for an example.
Related
I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.
I try to do something like this:
// Note: T object may have several functions with the name foo, but with different signatures.
// a function foo also can be a template one with variadic parameters pack.
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template<typename U>
static bool test(decltype(&U::foo));
template<typename U>
static float test(...);
public:
static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;
//-------------------------------------------------------------^^^^^^^^^
// how to do it?
};
I would like to use it for declaring specific object at compile time - something like this:
class Bar
{
public:
template<typename T, typename...Args>
void doSomthing(T* p, Args&&...parameters)
{
// get correct object type:
// if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;
// compute
ObjType::doSomthing(p, std::forward<Args>(parameters)...);
}
private:
struct A
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
p->foo(std::forward<Args>(parameters)...);
}
};
struct B
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
// do something else
}
};
};
Something like this, perhaps:
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template <typename U>
static std::true_type test(
typename std::enable_if<sizeof(
decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
);
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
Demo
I am trying to create class deriving from variadic template. Here is the code:
struct Some { };
template < class Base, class T >
struct Feature
{
protected:
void DoStuff(T& t) { }
};
template < class T, class ... Ts >
struct MultiFeature
: public Feature< T, Ts >...
{
};
class TestFeature
: public MultiFeature< Some, std::int16_t, std::string >
{
public:
void TestDoStuff()
{
std::int16_t i;
DoStuff(i);
}
};
Feature should be a simple wrapper around some basic type (in this case, integer and string), providing some functionality to class deriving from it. MultiFeature is used so that I do not have to derive from Feature< std::int16_t >, Feature< std::string >.
As far as I understand, there should be no ambiguity in this case, because there are two different DoStuff functions, each taking different parameter type, however VS2017 complains about ambiguous access. Is this correct behavior? If so, is there any simple workaround around this problem?
EDIT
It seems that compiler is right here, however in this answer, suggested workaround for this is to bring base class member functions into scope with using (Ambiguous access to base class template member function). Is it somehow possible to do this for variadic template base class?
It seems that compiler is right here, however in this answer, suggested workaround for this is to bring base class member functions into scope with using (Ambiguous access to base class template member function). Is it somehow possible to do this for variadic template base class?
If you can use C++17, it's trivially simple
template <typename T, typename ... Ts>
struct MultiFeature : public Feature<T, Ts>...
{
using Feature<T, Ts>::DoStuff...;
};
Unfortunately the variadic using is introduced in C++17 so, in C++11 and C++14, the best I can imagine is a MultiFeature recursive definition
// ground case: a fake DoStuff to abilitate following using
template <typename T, typename ... Ts>
struct MultiFeature
{ void DoStuff () { } };
// recursion case
template <typename T, typename T0, typename ... Ts>
struct MultiFeature<T, T0, Ts...>
: public Feature<T, T0>, public MultiFeature<T, Ts...>
{
using Feature<T, T0>::DoStuff;
using MultiFeature<T, Ts...>::DoStuff;
};
The following is a full compiling example (with both cases)
struct Some { };
template <typename, typename T>
struct Feature
{
protected:
void DoStuff (T &) { }
};
#if 0
template <typename T, typename ... Ts>
struct MultiFeature : public Feature<T, Ts>...
{
using Feature<T, Ts>::DoStuff...;
};
#else
// ground case: a fake DoStuff to abilitate following using
template <typename T, typename ... Ts>
struct MultiFeature
{ void DoStuff () { } };
// recursion case
template <typename T, typename T0, typename ... Ts>
struct MultiFeature<T, T0, Ts...>
: public Feature<T, T0>, public MultiFeature<T, Ts...>
{
using Feature<T, T0>::DoStuff;
using MultiFeature<T, Ts...>::DoStuff;
};
#endif
struct TestFeature
: public MultiFeature<Some, short, int, long, long long>
{
void TestDoStuff ()
{ int a{}; DoStuff(a); }
};
int main ()
{
TestFeature tf;
}
Is it possible to pass pointers-to-member as variadic template arguments. I can't seem to figure out the syntax.
for a function call it works like this:
struct A
{
int a;
float b;
}
template <typename ... TArgs> void f(A *obj, TArgs ... params)
{
void *members[] { (&(obj->*params))... };
// ... do something ...
}
That can be used like this:
f(obj, &A::a, &A::b);
I would like to pass params in a similar fashion to a class template
template <[something] ... params> class Foo
{
void Bar(A *obj)
{
void *members[] { (&(obj->*params))... };
// ... do something ...
}
};
That should be used like this:
Foo<&A::a, &A::b> foo;
foo.bar(obj);
I'm having trouble figuring out what [something] should be.
If member type is known and there is only one parameter, it can be done like this:
template <int A::*ptr> //...
Is there a way to generalize this for variadic parameter list of member pointers where members are of different unknown beforehand types?
Update: Variadic argument pack for member pointers of fixed known types is declared like so:
template<int A::*...ptr> struct Foo {};
Now I just need to replace int with typename that can be deduced.
And with C++17, following works perfectly:
template<auto A::*...ptr> struct Foo {};
Unfortunately I need a solution that will work with C++14
In C++14, you can use another level of indirection to do that:
struct A {
int a;
float b;
};
template<typename... T>
struct Bar {
template <T A::*... params>
struct Foo {
void Bar(A *obj) {
void *members[] { (&(obj->*params))... };
// ... do something ...
(void)members;
}
};
};
int main() {
A a;
Bar<int, float>::Foo<&A::a, &A::b> foo;
foo.Bar(&a);
}
auto keyword (introduced with the C++17 for non-type template parameters, as you mentioned) solves more or less this kind of issues. Think of std::integral_constant and how would it be more user-friendly if you hadn't to specify each time the type as the first argument...
I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.
Using variadic template arguments together with a simple template argument I have experienced some strange behaviour of is_base_of when it was instantiated from a binded functor.
Here is the code:
template <class T, class Index>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T,First>
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B,int> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(1 ,3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 1, 3.14)()<<std::endl; // output is 0 but it should be 1 !
return 0;
}
The program output is:
0
1
0
But I would expect:
0
1
1
Am I using the variadic templates in a wrong way? Is there any other (correct) way to get the first type of a variadic type list like Args? Why this is a problem only when it is used with the bind expression?
Note, if I am modifing the Base template to have only one template parameter, then the bind expression works:
template <class T>
class Base{};
template<typename T>
struct Checker {
typedef int result_type;
// Returns 1 if a given T type is descendant of Base<T>
template<typename ...Args>
result_type operator()(Args&&... params)
{
return check(std::is_base_of<Base<T>, T>(),
std::forward<Args>(params)...);
}
template<typename ...Args>
result_type check(const std::true_type&, Args&&... params)
{
return 1;
}
template<typename ...Args>
result_type check(const std::false_type&, Args&&... params)
{
return 0;
}
};
struct A {};
struct B : Base<B> {};
int main()
{
Checker<A> ch1;
std::cout<<ch1(3.14)<<std::endl;
Checker<B> ch2;
std::cout<<ch2(3.14)<<std::endl; // output is 1
std::cout<<std::bind(ch2, 3.14)()<<std::endl; // output is 1 this time!
return 0;
}
You're not getting the expected output because the data-type of First in your Checker function object when called after std::bind() is of type int&, not int.
Therefore std::is_base_of<Base<B,int&>, B> does not instantiate to a std::true_type for the call to Checker::check.
The problem is that std::bind is creating an object that internally stores the arguments for the function you are passing to it. Therefore there is a named l-value as a non-static data-member of the object returned by std::bind that is holding the value you passed as an argument to be bound to your function. When that non-static data-member is then passed to the r-value reference at the time you call the operator() of the functor, it's passed as an l-value reference, since it is no longer a temporary object. You would have a similar problem if you did something like:
int x = 1;
Checker<B> ch2;
std::cout<<ch2(x, 3.14)<<std::endl;
The named-value x is an l-value, and would be passed to the first argument in your operator() method as an l-value reference, not as temporary, since first is a r-value reference. Therefore your type would end up again as an int& and not an int, and you'd print a value of 0.
To fix this problem, you can do something like:
template<typename First, typename ...Args>
result_type operator()(First&& first, Args&&... params)
{
if (std::is_reference<First>::value)
{
return check(std::is_base_of<Base<T, typename std::remove_reference<First>::type>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
else
{
return check(std::is_base_of<Base<T,First>, T>(),
std::forward<First>(first),
std::forward<Args>(params)...);
}
}
This will strip off the reference-type of the object and give you the results you want.
Unfortunately std::is_reference did not give me the expected result on a more complicated issue.
So finally I choosed providing the reference and const-reference overloads:
template<typename First, typename ...Args>
result_type operator()(First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}
template<typename First, typename ...Args>
result_type operator()(const First& first, Args&&... params)
{
return check(std::is_base_of<Base<T,First>, T>(),
first,
std::forward<Args>(params)...);
}