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...
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 templatize some of my code and am not sure if i am doing it correct way ?
template <typename T>
class User
{
public:
template <typename T>
void foo() {
A* pa = funcA();
OR
B* pb = funcB();
//common code follows
....
....
....
};
User<Atype> C1;
User<Btype> C2;
In the above code I am looking as to how to define foo() as to be able to use
either of A* pa = funcA() or B* pb = funcB() based on how the class is instantiated. C1 should be able to use A* pa = funcA() and C2 should be able to use B* pb = funcB().
Not directly, but there is various options. Normally it is best to avoid designs that result in needing different named functions, or conceptually different operations.
For example if both A and B had a member or static function foo, then you could call that (x.foo(), T::foo(), etc.) instead of having the separately named funcA and funcB. Or similarly, in the case of parameters you can use function overloading (as you can't overload on the return type), such as std::to_string, and sometimes using templates as well such as std::swap.
Otherwise, if you need to support completely different things, then there are many options.
You can specialise foo to have different implementations for different types. This is often not particularly ideal if you are planning to use many different types with a template function or class. In some cases you might specialise the entire class, and there is also partial specialisation.
class A {};
class B {};
A *funcA();
B *funcB();
template <typename T>
class User
{
public:
void foo();
};
template<> void User<A>::foo()
{
auto a = funcA();
// ...
}
template<> void User<B>::foo()
{
auto ab = funcB();
// ...
}
Similar to 1, you can have a separate template function or class that is specialised.
class A {};
class B {};
A *funcA();
B *funcB();
template<class T> T *funcGeneric();
template<> A *funcGeneric<A>() { return funcA(); }
template<> B *funcGeneric<B>() { return funcB(); }
template <typename T>
class User
{
public:
void foo()
{
auto p = funcGeneric<T>();
}
};
Or with a class, which can be useful if you have multiple methods or pieces of information. For a single method, the call operator is often overloaded.
template<class T> class FuncGeneric;
template<> class FuncGeneric<A>
{
public:
A *operator()()const { return funcA(); }
};
template<> class FuncGeneric<B>
{
public:
B *operator()()const { return funcB(); }
};
template <typename T>
class User
{
public:
void foo()
{
auto p = FuncGeneric<T>()();
}
};
Extending on 2, but you pass the "adapter" as a template parameter itself. This is one you see in the STL a fair bit, with things like std::map taking the Compare parameter (default std::less), unique_ptr taking a deleter (with std::default_delete calling delete), hash functions, etc.
template<class T> class FuncGeneric;
template<> class FuncGeneric<A>
{
public:
A *operator()()const { return funcA(); }
};
template<> class FuncGeneric<B>
{
public:
B *operator()()const { return funcB(); }
};
template <class T, class Func = FuncGeneric<T>>
class User
{
public:
void foo()
{
auto p = Func()();
}
};
In some cases you might pass the function itself. More common for functions rather than classes, for example many of the algorithms (e.g. find_if) do this.
template <class T, class Func>
class User
{
public:
User(Func func) : func(func) {}
void foo()
{
auto p = func();
}
private:
Func func;
};
int main()
{
User<A, A*(*)()> user(&funcA);
}
Functions can also be a template parameter themselves, although this is fairly uncommon.
template <class T, T*(*Func)()>
class User
{
public:
void foo()
{
auto p = Func();
}
};
int main()
{
User<A, &funcA> user;
}
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.
I have a template class TC who's constructor takes parameters who's values are dependent on, as well as being of type Tn.
So, I want to create a helper template function htf that will call the same functions of a Tn object to generate a TC for a set of types X0 to Xn. The helper function takes only one parameter from that set. Is it possible, perhaps with variadic templates, to write the function once for the set of types, instead of having to write the same function over and over again for each type?
Now, I could just use a template to allow all types, but I don't want that as there may be another function with the same name written for a specific type later that's not based on this TC. And, IIRC I think SFINAE works with member functions, not pure functions.
This is just an idea in my head at the moment, that's why the question is very general. However, here is roughly the code I'm thinking of, simplified, in an more concrete and in an over generalized fashion:
struct X0
{
int value;
int& fn() { return value; }
};
struct X1
{
double value;
double& fn() { return value; }
};
struct X2
{
float value;
float& fn() { return value; }
};
struct Y0 // don't accept this class in helper function
{
int value;
int& fn() { return value; }
};
template<typename T1, typename Tn>
class TC
{
T1* m_pT1;
Tn* m_pTn;
TC(T1* pT1, Tn* pTn) : m_pT1(pT1), m_pTn(pTn) {}
friend TC htf(Tn& tn);
public:
~TC() {}
};
// concrete functions:
TC<int, X0> htf(C0& x) { return TC<int, X0>(&x.fn(), &x); }
TC<double, X1> htf(C1& x) { return TC<double, X1>(&x.fn(), &x); }
TC<float, X2> htf(C2& x) { return TC<float, X2>(&x.fn(), &x); }
// or in an over generalized template function but it'll accept
// Y0 and others which I don't want:
template<typename X>
auto htf(X& x) -> TC<decltype(x.fn()), X>
{
return TC<decltype(x.fn()), X>(&x.fn(), &x);
}
So the htf function that I want is to work for classes X0, X1, and X2, but not Y0. However, I don't want it to interfere with any other function called htf that takes a parameter of type Y0, or any other type for that matter.
Additional
Is it possible to make it so that the collection of accepted classes can also include template classes taking an specified (or unspecified) number of parameters?
Write a function that is only enabled when a trait is true, then specialize it for all the desired types.
template<typename T>
struct enable_htf : std::false_type { };
template<>
struct enable_htf<X0> : std::true_type { };
template<>
struct enable_htf<X1> : std::true_type { };
// etc.
template<typename T, bool enable = enable_htf<T>::value>
struct htf_helper { };
template<typename T>
struct htf_helper<T, true>
{
using type = TC<decltype(std::declval<T&>().fn()), T>;
};
template<typename X>
typename htf_helper<X>::type
htf(X& x)
{
return { &x.fn(), &x };
}
But it seems you want something like this instead:
template<typename Needle, typename... Haystack>
struct is_one_of;
template<typename Needle, typename Head, typename... Tail>
struct is_one_of<Needle, Head, Tail...>
: conditional<is_same<Needle, Head>::value, true_type,
is_one_of<Needle, Tail...>>::type
{ };
template<typename Needle>
struct is_one_of<Needle> : false_type
{ };
template<typename X,
typename Requires = typename enable_if<is_one_of<X, X0, X1, X2>::value>::type>
auto
htf(X& x) -> TC<decltype(x.fn()), X>
{
return { &x.fn(), &x };
}
But personally I don't consider that clearer, even if is_one_of is reusable elsewhere.
This is an even more simplified version of my original question, but it relates to enabling a template function based on the type passed to it being part of a list of accepted types.
class A{};
class B{};
class C{};
class D{};
class collection1 : A, B, C {};
class collection2 : D {};
template<typename X>
typename std::enable_if<std::is_base_of<X, collection1>::value, X>::type fn(X x)
{
return X();
}
Then the following would work appropriately:
fn(A()); // works
fn(B()); // works
fn(C()); // works
fn(D()); // compile time failure
Having a 2nd function like this:
template<typename X>
typename std::enable_if<std::is_base_of<X, collection2>::value, X>::type fn(X x)
{
return X();
}
Would result in:
fn(A()); // works
fn(B()); // works
fn(C()); // works
fn(D()); // works
Using this method, I can enable function fn to work with types I want and not others and I can write the list with ease. Also, this should be faster than iterating through a list of variadic template parameters.
Thanks Jonathan Wakely, you helped a lot in my thought process. I just thought that this is simpler and can be made even clearer if I use a helper template which would encapsulate the enable_if clause which would be good as I have many other functions that would require this.
Additional
Looks like this answer isn't good enough as I need to be able to determine if a template class is in the collection I'm looking for.
I thought that template specializations were fully independent entities and could have whatever they wanted. But VC++ threw me an error when I made the return type of a specialization different to the return type of the original template. Is that really Standard? I worked around it easily by moving the function body into a static class.
There is no function template partial specialization, because there's overloading of functions (and function templates. However, function overloading is much more limited than template specialization, so what you usually do, is to fall back on class template specializations:
template< typename R, typename T >
struct foo_impl {
static R foo(T)
{
// ...
return R(); // blah
}
};
template< typename T >
struct foo_impl<void,T> {
static void foo(T)
{
// ...
}
};
template< typename R, typename T >
R foo(T obj);
{
return foo_impl<R,T>::foo(obj); // fine even if R is void
}
Function specialization is weird and almost non-existent. It's possible to fully specialize a function, while retaining all types - i.e. you're providing a custom implementation of some specialization of the existing function. You can not partially specialize a templated function.
It's likely that what you're trying to do can be achieved with overloading, i.e.:
template <typename T> T foo(T arg) { return T(); }
float foo(int arg) { return 1.f; }