I am trying to use perfect forwarding with parameter pack definitions made for a whole class, not just for the specific function.
example:
#include <tuple>
template<typename Ret, typename... Params>
class Example {
public:
Ret call(Params&&... data)
{
}
template <typename ...TParams> Ret
call1(TParams&&... data)
{
}
private:
};
int main() {
Example<void, int, short> example;
int i = 32;
//example.call(i, 0);
example.call1(i, 0);
}
But the compiler makes a difference between call and call1. I thought that both examples shall work. If you uncomment "call" the compiler gives the error:
" rvalue reference to type 'int' cannot bind to lvalue of type 'int'"
My problem exactly:
I wanted to create a call-system where you can derive and override the call function. But you can't override templated functions.
If I use it without the Rvalue-References it's working fine. But since my architecture has at least one deeper call since the calling class is just derived by another class which has the same template with that parameter pack which then is std::forwarded. That's where I came to the topic of perfect forwarding, which is not useable this way.
So the idea was to use it like this:
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params&&... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
//MyDerived.call(i, 0);
MyDerived.call1(i, 0);
}
But of course this does not work.
So using it without "&&" does work but as said with the additional stack-memory per deeper call.
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
MyDerived.call(i, 0);
MyDerived.call1(i, 0);
}
It works if you pass the parameters by std::move :
#include <tuple>
template<typename Ret, typename... Params>
class Base {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class Derived : public Base<Ret, Params...> {
public:
Ret call(Params&&... data)
{
Base<Ret, Params...>::call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
};
int main() {
Derived<void, int, short> MyDerived;
int i = 32;
MyDerived.call(std::move(i), std::move(0));
MyDerived.call1(i, 0);
}
Besides this produces a load of code, I do not want the Users of my API to always use std::move, just pass the parameters as normal.
To complexify a bit, an additional case which shall also work the same behaviour but with a composit instead of an inheritance. This leads definetely to an additional stack allocation of the pack expansion for the call of the Composit, which I want to optimize, since this is not needed:
#include <tuple>
template<typename Ret, typename... Params>
class Composit {
public:
Ret call(Params&&... data)
{
}
};
template<typename Ret, typename... Params>
class MainClass {
public:
MainClass() : callee(new Composit<Ret, Params...>())
{}
Ret call(Params&&... data)
{
callee->call(std::forward<Params>(data)...);
}
template <typename ...TParams> Ret
call1(TParams&& ...)
{
}
private:
Composit<Ret, Params...>* callee;
};
int main() {
MainClass<void, int, short> MyClass;
int i = 32;
MyClass.call(std::move(i), std::move(0));
//MyClass.call1(i, 0);
}
Is there any solution to solve this problem without std::move?
Code was run on a clang-compiler: https://godbolt.org/z/vecsqM9sY
You can simply copy the examples inside.
TLDR: template parameter matching against T&& results in one of 4 reference types: T&, T&&, const T&, const T&&. When automatic parameter matching is not possible and you specify the template parameter manually at a class level instead, then you basically have to pick one of these 4 reference types. E.g.: Derived<void, const int&, const short&> MyDerived; Perfect forwarding will still work in the sense it will perfectly forward the type you chose. But it will not directly work if you only want to specify the base type T and want the member function to work for either of these 4 reference types.
More detailed answer following:
Template parameter with perfect forwarding allows all 4 possible reference types of a base type myclass passed to a function template<typename T> A(T&& var) to be forwarded perfectly to another function template<typename T> B(T&& var). But first let's look at how these possible reference types passed to A are matched to T:
myclass& => matches using T=myclass&
const myclass& => matches using T=const myclass&
myclass&& => matches using T=myclass, but T=myclass&& has the same result
const myclass&& => matches using T=const myclass, but T=const myclass&& has the same result
The basic trick in this matching is that you can combine reference types & and && in type declarations and these are resolved as follows:
myclass & && results in myclass &
myclass && && results in myclass &&
myclass && results in myclass &&
First, looking at the possible parameter matchings, then the end results are all references, but the deducted template parameter is one of four: myclass&, const myclass&, myclass, const myclass.
Second, as you can see if you give myclass as template parameter that essentially implies myclass&& as function parameter.
This happens in your example: since you specify only the base type (int, short) as template parameter, this implies an rvalue reference parameter in your member function specification.
I would suggest to avoid using base type names myclass and always choose which reference type you want explicitly, since template parameter T=myclass&& also implies function parameter type myclass&&.
So what about perfect forwarding? If var was an rvalue reference for A then, as a named variable, it automatically gets converted to an lvalue reference when passed to B. Thus you cannot directly forward rvalue references. This can be solved via std::forward which converts an lvalue reference back to an rvalue reference when T=myclass, T=const myclass, T=myclass&& or T=const myclass&&. But this crucially depends on the original template matching for A.
Lastly, one of the problems with the current solution is that it is not flexible when you want to pass both named variables (i) and unnamed variables/explicit values (0). This is because named variables of type T=int can be bound to:
T&
const T&
but not to T&&
While an explicit value (or unnamed variable on the right hand) of type T=int can be bound to:
T&&
const T&&
const T&
but not to T&
So if you are not modifying the variable then T=const int& can be bound to all cases. But when you want to modify the variable then it makes sense to choose int&, but that doesn't allow passing explicit values (like 0).
Though that does not seem to be question here, but I think it would be possible in theory to specify the base type at class level and have templated member functions that would then take one of the 4 reference types. But that would require a more intricate solution and templated member functions in the base class and derived classes.
Related
Trying to pass a lambda function to a template factory function which is templated on the function arguments of the passed function leads gcc-10.2.0 to report no matching function for call to ‘test(main()::<lambda(int, double)>)’.
It does seem to work when I add a + in front of the lambda function forcing the conversion to a function pointer, but I don't see why that would be necessary. Why does the conversion not happen automatically? Is there any way to make this work?
I have also tried std::function<void(TArgs...)> test_func as argument in the declaration of make_test, however that gives me the same no matching function for call error.
#include <iostream>
template <typename... TArgs>
struct test_type {
test_type(void(TArgs...)) {};
};
template <typename... TArgs>
test_type<TArgs...> make_test(void test_func(TArgs...)) {
return test_type<TArgs...>{test_func};
}
int main() {
auto test_object = make_test([](int a, double b) { std::cout << a << b << "\n"; });
return 0;
}
Edit
I was wondering if there maybe is some way to make it work with type traits. Something like the following. Although I know of no way to get the argument list from the template parameter.
template <typename F>
test_type<get_arg_list<F>> make_test(std::function<F>&& f) {
return test_type<get_arg_list<F>>{std::forward(f)};
}
In order to support a variety of callables being passed to your factory (e.g., a stateful lambda or a function pointer), your test_type constructor should accept some kind of type-erased function type like std::function<void(int, double)>:
template<class... TArgs>
struct test_type {
test_type(std::function<void(TArgs...)>) {};
};
Afterwards it's just a matter of writing the boilerplate to handle the following callables being passed to make_test
a regular function pointer
a lambda (struct with a operator()(...) const)
a mutable lambda or a user defined callable without a const operator() function
Here is one approach using type traits:
Start with a base class that we'll specialize for each scenario:
template<class T, class = void>
struct infer_test_type;
(This is a common setup for the voider pattern. We can do this with concepts and constraints, but I'm feeling too lazy to look up the syntax, maybe later)
Regular function pointer specialization
template<class Ret, class... Args>
struct infer_test_type<Ret(*)(Args...)>
{
using type = test_type<Args...>;
};
Now we can write a templated alias for simplicity:
template<class T>
using infer_test_type_t = typename infer_test_type<T>::type;
And we can verify that it works like so:
void foo(int, double){}
// ...
static_assert(std::is_same_v<infer_test_type_t<decltype(&foo)>, test_type<int, double>>);
We can use the type trait for our make_test function like so:
template<class T>
auto make_test(T&& callable) -> infer_test_type_t<T>
{
return infer_test_type_t<T>{std::forward<T>(callable)};
}
Now it's just a matter of covering our other two scenarios.
Callable objects
these will have operator() (either const or not)
I'll start with a top level trait to detect the presence of operator() and feed the type of operator() into another trait.
The top level trait:
// if T is a callable object
template<class T>
struct infer_test_type<T, std::void_t<decltype(&T::operator())>>
{
using type = typename infer_test_type<decltype(&T::operator())>::type;
};
You see that internally it's calling back into another infer_test_type specialization that I haven't shown yet; one that is specialized for operator(). I'll show the two specializations now:
// if operator() is a const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...) const>
{
using type = test_type<Args...>;
};
// if operator() is non-const member function
template<class T, class Ret, class... Args>
struct infer_test_type<Ret(T::*)(Args...)>
{
using type = test_type<Args...>;
};
(We could probably combine these two if we wanted to be a little bit smarter and lop off any const at the high level before calling down, but I think this is more clear)
And now we should be able to infer an appropriate test_type for non-generic callables (no generic lambdas or templated operator() functions):
a test with a non-const operator():
struct my_callable
{
void operator()(int, double) // non-const
{
}
};
// ...
static_assert(std::is_same_v<infer_test_type_t<my_callable>, test_type<int, double>>);
And a test with your lambda:
auto lambda = [](int a, double b) { std::cout << a << b << "\n"; };
static_assert(std::is_same_v<infer_test_type_t<decltype(lambda)>, test_type<int, double>>);
Putting it all together
For your simple (non-capturing, non-generic lambda) example it's quite straightforward:
make_test([](int a, double b) { std::cout << a << b << "\n"; });
Demo
How do I pass an object with a derived template instantiation to a method accepting those objects with a base template instantiation?
It seems possible, as std::shared_ptr or std::pair seem capable to do it.
E.g.
#pragma once
#include <iostream>
#include <memory>
struct Base {
virtual void print() = 0;
};
struct Derived : public Base {
void print() {
std::cout << "Got it!" << std::endl;
}
};
void printBase(const std::shared_ptr<Base> &ptr){
ptr->print();
}
void printBase(const std::pair<Base&, Base&> &pr){
pr.first.print();
}
template <typename T>
struct Wrap {
T& t;
};
void printBase(const Wrap<Base> &wrap) {
wrap.t.print();
}
int main() {
Derived d;
std::shared_ptr<Derived> ptr = std::make_shared<Derived>(d);
printBase(ptr); // works
std::pair<Derived&, Derived&> pr = {d, d};
printBase(pr); // works
Wrap<Derived> w = Wrap<Derived>{d};
// printBase(w); // gives compile error
}
You will need to explicitly add a conversion constructor and/or assignment operator to your Wrapped type to be able to convert from different types.
This is how both std::shared_ptr and std::pair do this internally; shared_ptr<T> can be constructed from shared_ptr<U> types (with SFINAE restrictions that U* is convertible to T*), and pair<T,U> can be constructed from pair<T2,U2> types (with SFINAE restrictions that T2 is convertible to T and U2 is convertible to U).
Doing this can be as simple as adding a new constructor:
template <typename T>
struct Wrap
{
Wrap(T& ref)
: t{ref}
{
}
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U&, T&>>>
Wrap(const Wrap<U>& other)
: t{other.t}
{
}
T& t;
};
The above example uses is_convertible as a condition for enable_if so the constructor is only visible when references of U can be converted to references of T. This will constrain it such that U must be hierarchically related to T (since references aren't convertible otherwise) -- which would allow a Wrapped<Derived> to be converted to Wrapped<Base>, but not vice-versa.
Edit: As mentioned in the comments, it's worth noting that, unlike types that are part of a hierarchy -- where a reference to Derived can be passed as a reference to Base, types that wrap hierarchies will not be able to pass a reference to a Template<Derived> as a reference to a Template<Base>.
The examples with a std::shared_ptr<Derived> being passed to a const std::shared_ptr<Base>& only actually work due to const-lifetime extension in C++. This doesn't actually pass it as a reference -- but instead materializes a temporary object of std::shared_ptr<Base> which gets passed to the reference. It's effectively the same as passing-by-value.
This also means that you cannot have a Template<Derived> be passed to a non-const Template<Base> reference, since lifetime extension only occurs for const references.
Edit: As discussed in the comments:
Making the constructor a copy conversion is not required; it could easily be an R-value constructor instead. However, if you are doing cleanup on destruction of the wrapped type, then you will need to somehow flag that the moved-from object does not need to be cleaned up. The easiest way is using pointers, where you rebind to nullptr after moving:
template <typename T>
struct Wrap
{
Wrap(T& ref)
: t{std::addressof(ref)}
{
}
Wrap(Wrap&& other)
: t{other.t}
{
other.t = nullptr;
}
Wrap(const Wrap&) = delete;
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U&, T&>>>
Wrap(Wrap<U>&& other)
: t{other.t}
{
other.t = nullptr;
}
~Wrap() {
if (t != nullptr) {
cleanup(*t); // some cleanup code
}
}
T* t;
};
If pointers aren't possible for your desired API, then you may need to use a bool needs_cleanup that gets set appropriately during moves, since references cannot be rebound.
Note: if the data is private and not public as in this example, you may need to have a friend declaration of:
template <typename> friend class Wrap;
So that a Wrap<T> may access the private data members of a Wrap<U>.
Change printBase function to the following one:
template <typename T, typename = std::enable_if<std::is_base_of_v<Base, T>>>
void printBase(const Wrap<T> &wrap){
wrap.t.print();
}
I am trying to write a class template that uses a parameter-pack and implements a member function for each type contained in the parameter-pack.
This is what I have so far:
template <typename...T>
class Myclass {
public:
void doSomething((Some_Operator_to_divorce?) T) {
/*
* Do Something
*/
std::cout << "I did something" << std::endl;
}
};
My goal is to have a class template that can be used in the following way:
Myclass<std::string, int, double> M;
M.doSomething("I am a String");
M.doSomething(1234);
M.doSomething(0.1234);
Where the class template mechanism will create an implementation for a doSomething(std::string x), a doSomething(int x) and a doSomething(double x) member function but not a doSomething(std::string x, int i, double f) member function.
I found a lot of examples in the web on the usability of parameter-packs, but I could not figure out if it can be used for my purpose, or if I totally misunderstood for what a parameter-pack can be used.
I thought that I need to unpack the parameter-pack but, after reading a lot of examples about unpacking parameter packs, I believe that this is not the right choice and it has a complete different meaning.
So, therefore, I am looking for a operation to "divorce" a parameter-pack.
There is no "operator" specifically that supports this, but what you're requesting can be done in a few different ways, depending on your requirements.
The only way to "extract" T types from a parameter pack of a class template with the purpose of implementing an overload-set of functions is to implement it using recursive inheritance, where each instance extracts one "T" type and implements the function, passing the rest on to the next implementation.
Something like:
// Extract first 'T', pass on 'Rest' to next type
template <typename T, typename...Rest>
class MyClassImpl : public MyClassImpl<Rest...>
{
public:
void doSomething(const T&) { ... }
using MyClassImpl<Rest...>::doSomething;
};
template <typename T>
class MyClassImpl<T> // end-case, no more 'Rest'
{
public:
void doSomething(const T&) { ... }
};
template <typename...Types>
class MyClass : public MyClassImpl<Types...>
{
public:
using MyClassImpl<Types...>::doSomething;
...
};
This will instantiate sizeof...(Types) class templates, where each one defines an overload for each T type.
This ensures that you get overload semantics -- such that passing an int can call a long overload, or will be ambiguous if there are two competing conversions.
However, if this is not necessary, then it'd be easier to enable the function with SFINAE using enable_if and a condition.
For exact comparisons, you could create an is_one_of trait that only ensures this exists if T is exactly one of the types. In C++17, this could be done with std::disjunction and std::is_same:
#include <type_traits>
// A trait to check that T is one of 'Types...'
template <typename T, typename...Types>
struct is_one_of : std::disjunction<std::is_same<T,Types>...>{};
Alternatively, you may want this to only work if it may work with convertible types -- which you might do something like:
template <typename T, typename...Types>
struct is_convertible_to_one_of : std::disjunction<std::is_convertible<T,Types>...>{};
The difference between the two is that if you passed a string literal to a MyClass<std::string>, it will work with the second option since it's convertible, but not the first option since it's exact. The deduced T type from the template will also be different, with the former being exactly one of Types..., and the latter being convertible (again, T may be const char*, but Types... may only contain std::string)
To work this together into your MyClass template, you just need to enable the condition with SFINAE using enable_if:
template <typename...Types>
class MyClass
{
public:
// only instantiates if 'T' is exactly one of 'Types...'
template <typename T, typename = std::enable_if_t<is_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
// or
// only instantiate if T is convertible to one of 'Types...'
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T&) { ... }
};
Which solution works for you depends entirely on your requirements (overload semantics, exact calling convension, or conversion calling convension)
Edit: if you really wanted to get complex, you can also merge the two approaches... Make a type trait to determine what type would be called from an overload, and use this to construct a function template of a specific underlying type.
This is similar to how variant needs to be implemented, since it has a U constructor that considers all types as an overload set:
// create an overload set of all functions, and return a unique index for
// each return type
template <std::size_t I, typename...Types>
struct overload_set_impl;
template <std::size_t I, typename T0, typename...Types>
struct overload_set_impl<I,T0,Types...>
: overload_set_impl<I+1,Types...>
{
using overload_set_impl<I+1,Types...>::operator();
std::integral_constant<std::size_t,I> operator()(T0);
};
template <typename...Types>
struct overload_set : overload_set_impl<0,Types...> {};
// get the index that would be returned from invoking all overloads with a T
template <typename T, typename...Types>
struct index_of_overload : decltype(std::declval<overload_set<Types...>>()(std::declval<T>())){};
// Get the element from the above test
template <typename T, typename...Types>
struct constructible_overload
: std::tuple_element<index_of_overload<T, Types...>::value, std::tuple<Types...>>{};
template <typename T, typename...Types>
using constructible_overload_t
= typename constructible_overload<T, Types...>::type;
And then use this with the second approach of having a function template:
template <typename...Types>
class MyClass {
public:
// still accept any type that is convertible
template <typename T, typename = std::enable_if_t<is_convertible_to_one_of<T, Types...>::value>>
void doSomething(const T& v)
{
// converts to the specific overloaded type, and call it
using type = constructible_overload_t<T, Types...>;
doSomethingImpl<type>(v);
}
private:
template <typename T>
void doSomethingImpl(const T&) { ... }
This last approach does it two-phase; it uses the first SFINAE condition to ensure it can be converted, and then determines the appropriate type to treat it as and delegates it to the real (private) implementation.
This is much more complex, but can achieve the overload-like semantics without actually requiring recursive implementation in the type creating it.
I created a struct with two static functions for testing purposes. The first instance of f is called when an l-value reference is passed. The second instance is called when an r-value is passed:
template <typename _Tp>
struct T {
static constexpr void f(_Tp&) { std::cout << "f(T&) is called!\n"; }
static constexpr void f(_Tp&&) { std::cout << "f(T&&) is called!\n"; }
};
When I was experimenting with strong types, I found out the first instance, T::f(_Tp&) was called when I attempted to create the strong type implicitly. Why is this? (See following)
using T_int = T<int>;
T_int::f(
typename strong_types::create_strong_type<int, struct tag>(5)()
); // calls f::(T&) (?)
using KG = typename strong_types::create_strong_type<double, struct KG_tag>;
T_int::f(KG(4.2)()); // calls f(T&&)
Note that operator() returns the value given through the constructor.
Feel free to ask if I need to elaborate.
EDIT: strong_types is a namespace. It exists among other things of the alias create_strong_type:
namespace strong_type {
template <typename T, typename tag>
using create_strong_type = Strong_Type<T, tag>;
...
}
...
template <typename T, typename tag>
struct Strong_Type {
constexpr explicit Strong_Type(const T& value) : _value(value) {}
constexpr explicit Strong_Type(T&& value) : _value(std::move(value)) {}
constexpr T& operator()() noexcept { return _value; }
private:
T _value;
};
The difference is not due to using an alias (using), but to the type you pass as first template argument to create_strong_type. In one case, it's an int, and in the other, a double.
Try T<double>::f(KG(4.2)()); and you will see the argument is passed as lvalue reference (because of the return type of Strong_Type::operator(), which is T&).
I am writing a kind of container class, for which I would like to offer an apply method which evaluates a function on the content of the container.
template<typename T>
struct Foo
{
T val;
/** apply a free function */
template<typename U> Foo<U> apply(U(*fun)(const T&))
{
return Foo<U>(fun(val));
}
/** apply a member function */
template<typename U> Foo<U> apply(U (T::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
struct Bar{};
template class Foo<Bar>; // this compiles
//template class Foo<int>; // this produces an error
The last line yields error: creating pointer to member function of non-class type ‘const int’. Even though I only instantiated Foo and not used apply at all. So my question is: How can I effectively remove the second overload whenever T is a non-class type?
Note: I also tried having only one overload taking a std::function<U(const T&)>. This kinda works, because both function-pointers and member-function-pointers can be converted to std::function, but this approach effectively disables template deduction for U which makes user-code less readable.
Using std::invoke instead helps, it is much easier to implement and read
template<typename T>
struct Foo
{
T val;
template<typename U> auto apply(U&& fun)
{
return Foo<std::invoke_result_t<U, T>>{std::invoke(std::forward<U>(fun), val)};
}
};
struct Bar{};
template class Foo<Bar>;
template class Foo<int>;
However, this won't compile if the functions are overloaded
int f();
double f(const Bar&);
Foo<Bar>{}.apply(f); // Doesn't compile
The way around that is to use functors instead
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return f(decltype(bar)(bar)); });
Which also makes it more consistent with member function calls
Foo<Bar>{}.apply([](auto&& bar) -> decltype(auto) { return decltype(bar)(bar).f(); });
In order to remove the second overload you'd need to make it a template and let SFINAE work, e. g. like this:
template<typename T>
struct Foo
{
T val;
//...
/** apply a member function */
template<typename U, typename ObjT>
Foo<U> apply(U (ObjT::*fun)() const)
{
return Foo<U>((val.*fun)());
}
};
Alternatively, you could remove the second overload altogether, and use lambda or std::bind:
#include <functional> // for std::bind
template<typename T>
struct Foo
{
T val;
/** apply a member function */
template<typename U, typename FuncT>
Foo<U> apply(FuncT&& f)
{
return {f(val)};
}
};
struct SomeType
{
int getFive() { return 5; }
};
int main()
{
Foo<SomeType> obj;
obj.apply<int>(std::bind(&SomeType::getFive, std::placeholders::_1));
obj.apply<int>([](SomeType& obj) { return obj.getFive(); });
}
How can I effectively remove the second overload whenever T is a non-class type?
If you can use at least C++11 (and if you tried std::function I suppose you can use it), you can use SFINAE with std::enable_if
template <typename U, typename V>
typename std::enable_if<std::is_class<V>{}
&& std::is_same<V, T>{}, Foo<U>>::type
apply(U (V::*fun)() const)
{ return Foo<U>((val.*fun)()); }
to impose that T is a class.
Observe that you can't check directly T, that is a template parameter of the class, but you have to pass through a V type, a template type of the specific method.
But you can also impose that T and V are the same type (&& std::is_same<V, T>{}).