any_cast with std::any's and std::optional - c++

If I put a T into an std::any, I can get it with any_cast<T>(my_any). But does the standard (= C++17, in the ballot phase at the moment) include a function like any_cast<T>(optional<any> oa) which returns nullopt if oa is nullopt and std::any_cast<T>(oa.value()) otherwise? Or something along those lines?
Edit: Since people seem to be suggesting implementations, I'll also list what I use for now:
/* using magic here to select between boost/std::experimental/std versions */
template<typename T>
inline const optional<T> any_cast(const optional<any>& operand)
{
return operand ?
optional<T>(any_cast<T>(operand.value())) :
optional<T>(nullopt);
}

There is no mention of anything like that in the std::optional proposal or in the std::any proposal.
I suppose it would be trivial to implement using a continuation function, since the return type is different depending on the state of the optional object:
template <typename T, typename TOptional, typename TF>
void any_cast_or_nullopt(TOptional&& o, TF&& f)
{
if(!o) return;
f(std::any_cast<T>(*o));
}
Add static_assert and/or SFINAE where appropriate to constrain the function. The value *o should also be forwarded depending on o's value category. Example usage:
int out = -1;
std::optional<std::any> x;
x = 10;
any_cast_or_nullopt<int>(x, [&out](int value)
{
out = value;
});
assert(out == 10);

If std::optional had a bind (or and_then) member function (that is, a function on optional<T> which takes a T -> optional<U> and either invokes it or returns nullopt), then that's what you'd be looking for:
std::optional<std::any>> oa;
optional<T> opt_t = oa.bind([](std::any& v) -> std::optional<T> {
if (T* t = std::any_cast<T>(&v)) {
return *t;
}
else {
return std::nullopt;
}
});
or, if you really want to directly invoke any_cast<T> and deal with throwing, map:
optional<T> opt_t = oa.map([](std::any& v) {
return std::any_cast<T>(v);
});
std::optional has no continuation functions though, so you'd have to write those as non-member functions.

Related

How to flatten the nested std::optional?

note: this question was briefly marked as a duplicate of this, but it is not an exact duplicate since I am asking about std::optionals specifically. Still a good question to read if you care about general case.
Assume I have nested optionals, something like this(dumb toy example):
struct Person{
const std::string first_name;
const std::optional<std::string> middle_name;
const std::string last_name;
};
struct Form{
std::optional<Person> person;
};
and this spammy function:
void PrintMiddleName(const std::optional<Form> form){
if (form.has_value() && form->person.has_value() && form->person->middle_name.has_value()) {
std::cout << *(*(*form).person).middle_name << std::endl;
} else {
std::cout << "<none>" << std::endl;
}
}
What would be the best way to flatten this optional check?
I have made something like this, it is not variadic, but I do not care that much about that(I can add one more level(overload with membr3) if really necessary, and everything beyond that is terrible code anyway).
template<typename T, typename M>
auto flatten_opt(const std::optional<T> opt, M membr){
if (opt.has_value() && (opt.value().*membr).has_value()){
return std::optional{*((*opt).*membr)};
}
return decltype(std::optional{*((*opt).*membr)}){};
}
template<typename T, typename M1, typename M2>
auto ret_val_helper(){
// better code would use declval here since T might not be
// default constructible.
T t;
M1 m1;
M2 m2;
return ((t.*m1).value().*m2).value();
}
template<typename T, typename M1, typename M2>
std::optional<decltype(ret_val_helper<T, M1, M2>())> flatten_opt(const std::optional<T> opt, M1 membr1, M2 membr2){
if (opt.has_value() && (opt.value().*membr1).has_value()){
const auto& deref1 = *((*opt).*membr1);
if ((deref1.*membr2).has_value()) {
return std::optional{*(deref1.*membr2)};
}
}
return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto flat = flatten_opt(form, &Form::person, &Person::middle_name);
if (flat) {
std::cout << *flat;
}
else {
std::cout << "<none>" << std::endl;
}
}
godbolt
notes:
I do not want to switch away from std::optional to some better optional.
I do not care that much about perf, unless I return a pointer I must make copy(unless arg is temporary) since std::optional does not support references.
I do not care about flatten_has_value function(although it is useful), since if there is a way to nicely flatten the nested optionals there is also a way to write that function.
I know my code looks like it works, but it is quite ugly, so I am wondering if there is a nicer solution.
The operation you're looking for is called the monadic bind operation, and is sometimes spelled and_then (as it is in P0798 and Rust).
You're taking an optional<T> and a function T -> optional<U> and want to get back an optional<U>. In this case the function is a pointer to data member, but it really does behave as a function in this sense. &Form::person takes a Form and gives back an optional<Person>.
You should write this in a way that is agnostic to the kind of function. The fact that it's specifically a pointer to member data isn't really important here, and maybe tomorrow you'll want a pointer to member function or even a free function. So that's:
template <typename T,
typename F,
typename R = std::remove_cvref_t<std::invoke_result_t<F, T>>,
typename U = mp_first<R>>
requires SpecializationOf<R, std::optional>
constexpr auto and_then(optional<T> o, F f) -> optional<U>
{
if (o) {
return std::invoke(f, *o);
} else {
return std::nullopt;
}
}
This is one of the many kinds of function declarations that are just miserable to write in C++, even with concepts. I'll leave it as an exercise to properly add references into there. I choose to specifically write it as -> optional<U> rather than -> R because I think it's important for readability that you can see that it does, in fact, return some kind of optional.
Now, the question is how do we chain this to multiple functions. Haskell uses >>= for monadic bind, but in C++ that has the wrong association (o >>= f >>= g would evaluate f >>= g first and require parentheses). So the next closest chose of operator would be >> (which means something different in Haskell, but we're not Haskell, so it's okay). Or you could implement this borrowing the | model that Ranges does.
So we'd either end up syntactically with:
auto flat = form >> &Form::person >> &Person::middle_name;
or
auto flat = form | and_then(&Form::person)
| and_then(&Person::middle_name);
A different way to compose multiple monadic binds together is an operation that Haskell spells >=>, which is called Kleisli composition. In this case, it takes a function T -> optional<U> and a function U -> optional<V> and produces a function T -> optional<V>. This is something that is exceedingly annoying to write constraints for so I'm just going to skip it, and it would look something like this (using the Haskell operator spelling):
template <typename F, typename G>
constexpr auto operator>=>(F f, G g) {
return [=]<typename T>(T t){
using R1 = std::remove_cvref_t<std::invoke_result_t<F, T>>;
static_assert(SpecializationOf<R1, std::optional>);
using R2 = std:remove_cvref_t<std::invoke_result_t<G, mp_first<R1>>>;
static_assert(SpecializationOf<R2, std::optional>);
if (auto o = std::invoke(f, t)) {
return std::invoke(g, *o);
} else {
// can't return nullopt here, have to specify the type
return R2();
}
};
}
And then you could write (or at least you could if >=> were an operator you could use):
auto flat = form | and_then(&Form::person >=> &Person::middle_name);
Because the result of >=> is now a function that takes a Form and returns an optional<string>.
Let's look at what the optimal form of a flatten function would look like. By "optimal" in this case, I mean the smallest presentation.
Even in the optimal case, at the point of performing the flatten operation, you would need to provide:
The optional<T> object to flatten.
The flatten operation function name.
A list of names, in order, to be indirected from at each flattening step.
Your code is very close to optimal. The only issue is that each name in the "list of names" must contain the typename of the member you're accessing at that level, which is something that hypothetically could be computed using knowledge of T.
C++ has no mechanism to do any better than this. If you want to access a member of an object, you must provide the type of that object. If you want to indirectly do this, C++ allows member pointers, but getting such a pointer requires knowing the type of the object at the point when the member is extracted. Even offsetof gymnastics would require using the type name when you're getting the offset.
Reflection would allow for something better, as you could pass compile-time strings that static reflection could use to fetch member pointers from the type currently in use. But C++20 has no such feature.
You've got a lot of helper functions for something that is fundamentally a chainable operation. And C++ has things for chains: operators. So I'd probably (ab)use operator* for this.
For your specific case, all you need is
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(
const std::optional<class_t>& opt,
const std::optional<member_t> class_t::*member)
{
if (opt.has_value()) return opt.value().*member;
else return {};
}
void PrintMiddleName2(const std::optional<Form> form){
auto middle = form * &Form::person * &Person::middle_name;
if (middle) {
std::cout << *middle;
}
else {
std::cout << "<none>" << std::endl;
}
}
But in reality you'd probably also want variants for non-optional members, getter methods, and arbitrary transforms, which I've listed here, though I'm not 100% certain they all compile properly.
//data member
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const std::optional<member_t> class_t::*member) {
if (opt.has_value()) return opt.value().*member;
else return {};
}
template<class class_t, class member_t>
std::optional<std::remove_cv_t<member_t>> operator*(const std::optional<class_t>& opt, const member_t class_t::*member) {
if (opt.has_value()) return {opt.value().*member};
else return {};
}
//member function
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(class_t::*member)()) {
if (opt.has_value()) return opt.value().*member();
else return {};
}
template<class class_t, class return_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(class_t::*member)()) {
if (opt.has_value()) return {opt.value().*member()};
else return {};
}
//arbitrary function
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, std::optional<return_t>(*transform)(arg_t&&)) {
if (opt.has_value()) return transform(opt.value());
else return {};
}
template<class class_t, class return_t, class arg_t>
std::optional<std::remove_cv_t<return_t>> operator*(const std::optional<class_t>& opt, return_t(*transform)(arg_t&&)) {
if (opt.has_value()) return {transform(opt.value())};
else return {};
}
http://coliru.stacked-crooked.com/a/26aa7a62f38bbd89

Allow implicit type conversion during template evaluation

I'm writing a wrapper class for C++ types, which allows me to instrument when a wrapped object is constructed, accessed, modified, and destroyed. To make this transparent for the original code, I include implicit conversion functions back to the underlying type, but this fails when a wrapped object is passed directly to a template since implicit conversions aren't evaluated. Here's some code that demonstrates this problem:
#include <utility>
// simplified wrapper class
template <typename T>
class wrap {
T t;
public:
wrap() : t() {}
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
};
// an example templated function
template <typename T>
bool is_same(const T& t1, const T& t2) { return t1 == t2;}
// second invocation fails due to template substitution failure
bool problem() {
wrap<int> w(5);
return is_same(static_cast<int>(w), 5) && is_same<>(w, 5);
}
I can resolve this manually by performing a static_cast on the wrapped variable at each template call site (as shown in the first invocation), but this doesn't scale well since I'm working with a large code base. Similar questions suggest inlining each template function as a friend function, but this also requires identifying and copying each template, which doesn't scale.
I'd appreciate any advice on how to (1) workaround this conversion problem with templated functions, or (2) otherwise instrument a variable at source-level without this problem.
The fault in this example lies with is_same. It declares that it requires two arguments of the same type, which is a requirement it does not need, and fails to require that type to have an ==, which it does need.
Granted, it is common to find C++ that poorly constrains template functions because it is difficult and verbose to do otherwise. Authors take a practical shortcut. That said, isn't the approach to fix the interface of is_same?
// C++17 version. Close to std::equal_to<>::operator().
template <typename T, typename U>
constexpr auto is_same(T&& t, U&& u)
noexcept(noexcept(std::forward<T>(t) == std::forward<U>(u)))
-> decltype(std::forward<T>(t) == std::forward<U>(u))
{
return std::forward<T>(t) == std::forward<U>(u);
}
With a corrected is_same, the code just works.
There are other examples one can imagine which may require two arguments to have the same type. For example, if the return type depends on the argument type and the return value can come from either:
template <typename T>
T& choose(bool choose_left, T& left, T& right) {
return choose_left ? left : right;
}
This is much rarer. But it might actually require thought to decide whether to use the underlying or wrapper type. If you have this enhanced behavior in the wrapper type, and conditionally use a wrapped value or an underlying value, should the underlying value be wrapped to continue to get the enhanced behavior, or do we drop the enhancement? Even if you could make this silently choose one of those two behaviors, would you want to?
However, you can still make it easier to get the value than to say static_cast<T>(...), for example by providing an accessor:
// given wrap<int> w and int i
is_same(w.value(), 5);
choose_left(true, w.value(), i);
I have a few other important comments:
wrap() : t() {}
This requires T be default constructible. = default does the right thing.
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
These are not explicit. A T is implicitly convertible to a wrap<T> and vice versa. This does not work well in C++. For example, true ? w : i is not well-formed. This causes std::equality_comparable_with<int, wrap<int>> to be false, which would be a reasonable requirement for is_same. Wrapper types should probably be explicitly constructed, and can be implicitly converted to the underlying type.
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
These are not ref-qualified, so they return lvalue references even if the wrapper is an rvalue. That seems ill-advised.
Finally, construction and conversion only take into account the exact type T. But any place T is used, it might be implicitly converted from some other type. And two conversions are disallowed in C++. So for a wrapper type, one has a decision to make, and that often means allowing construction from anything a T is constructible from.
With a pointer wrapper function it can work, if you treat the "inner" guy as a pointer.
This is not a complete solution, but should be a good starting point for you (for instance, you need to carefully write the copy and move ctors).
You can play with this code in here.
Disclaimer: I took the idea from Andrei Alexandrescu from this presentation.
#include <iostream>
using namespace std;
template <typename T>
class WrapperPtr
{
T * ptr;
public:
WrapperPtr(const WrapperPtr&){
// ???
}
WrapperPtr(WrapperPtr&&) {
// ???
}
WrapperPtr(const T & other)
: ptr(new T(other)) {}
WrapperPtr(T * other)
: ptr(other) {}
~WrapperPtr()
{
// ????
delete ptr;
}
T * operator -> () { return ptr; }
T & operator * () { return *ptr; }
const T & operator * () const { return *ptr; }
bool operator == (T other) const { other == *ptr; }
operator T () { return *ptr; }
};
// an example templated function
template <typename T>
bool my_is_same(const T& t1, const T& t2) { return t1 == t2;}
bool problem() {
WrapperPtr<int> w(5);
return my_is_same(static_cast<int>(w), 5) && my_is_same(*w, 5);
}

Is it possible to forward function calls with matching template type for a std::any-like container?

I haven't found a way to achieve what I want but I'm not knowledgeable enough to know if its impossible. Help would be appreciated.
The main data data container in our software behaves a bit like a std::variant or std::any: It has a base class BaseContainer that provides a type enum. The derived instance DataContainer holds the actual data in a typed tensor member variable. So a simplified example boils down to something like this:
BaseContainer* vContainer = new DataContainer<float>({1000000});
if (vContainer->getType() == DataTypes::FLOAT)
const Tensor<float>& vTensor = dynamic_cast<DataContainer<float>>(vContainer)->getData();
We have many methods that process data based on the underlying templated type and dimensions:
template<typename T>
void processData(const tensor<T>& aTensor, ...other arguments...);
The problem is, for every method like processData() that we want to call with a BaseContainer, we need to write a binding method that unravels the possible types to call the typed version of processData():
void processData(BaseContainer* aContainer) {
switch (vContainer->getType()) {
case DataTypes::INT8:
return processData(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
case DataTypes::UINT8:
return processData(dynamic_cast<DataContainer<uint8_t>>(vContainer)->getData());
case DataTypes::INT16:
return processData(dynamic_cast<DataContainer<int16_t>>(vContainer)->getData());
case DataTypes::UINT16:
return processData(dynamic_cast<DataContainer<uint16_t>>(vContainer)->getData());
...
default:
throw(std::runtime_error("Type not supported"));
}
}
My question is: Is it possible to make a single "adapter" method (in any released version of c++) that can take a function (like processData()), a BaseContainer and potentially a list of arguments, and invoke the correct template binding of this function with the arguments?
I failed to bind a template function dynamically because I was not able to pass the name without the template type. Yet the template type would need to be dynamic based on the BaseContainer. But maybe there are other means to achieve what I want to do? I'm very curious about any solution, mostly also to extend my understanding, as long as the complexity of the solution is below writing hundreds of adapter methods.
If nothing else, would it be possible to generate the "adapter" methods using preprocessor macros?
You cannot pass overloads by name, but you can pass functor with overloaded operator() as generic lambda have.
So
template <typename F>
auto dispatch(BaseContainer& vContainer, F f) {
switch (vContainer.getType()) {
case DataTypes::INT8:
return f(dynamic_cast<DataContainer<int8_t>&>(vContainer).getData());
case DataTypes::UINT8:
return f(dynamic_cast<DataContainer<uint8_t>&>(vContainer).getData());
case DataTypes::INT16:
return f(dynamic_cast<DataContainer<int16_t>&>(vContainer).getData());
case DataTypes::UINT16:
return f(dynamic_cast<DataContainer<uint16_t>&>(vContainer).getData());
...
default:
throw (std::runtime_error("Type not supported"));
}
}
with usage
dispatch(vContainer, [](auto* data){ return processData(data); });
If you are willing to write a small wrapper class for each processData-like function, you could do something like this:
// One like this for each function.
struct ProcessDataWrapper {
template <typename... Args>
static auto run(Args&&... args) {
return processData(std::forward<Args>(args)...);
}
};
template <typename Wrapper>
auto ProcessGeneric(BaseContainer* aContainer) {
switch (vContainer->getType()) {
case DataTypes::INT8:
return Wrapper::run(dynamic_cast<DataContainer<int8_t>>(vContainer)->getData());
// ...
}
// Called as
ProcessGeneric<ProcessDataWrapper>(myContainer);
It is possible, but as the comments say, it might be worth conidering std::visit.
Here's a solution requiring c++17 that only requires two lines for each function template you want to wrap. You could use a simple macro to simplify the wrpping further.
The core idea is to have a cast function that maps from a DataType enum to the correspondng DataContainer and then to leverage c++17 fold expressions to wrap the switch statement in your code.
Here's the cast function, so we have exactly one place to map from DataType to the actiual DataContainer:
template<DataType t>
constexpr inline decltype(auto) cast(BaseContainer& c) {
if constexpr(t == INT) return static_cast<DataContainer<int>&>(c);
else if constexpr(t == FLOAT) return static_cast<DataContainer<float>&>(c);
... map all other enum values ...
}
This is rather a convenience helper to make the following code a bit more readable. The next code block uses the c++17 fold expression to dispatch the function based on the type of the container.
template<DataType... types>
auto dispatcher_impl = [](auto f) {
// NB: capture by value here only for sake of readbility.
return [=](BaseContainer& c, auto... args) {
([&]{ if(c.GetDataType() == types ) { std::invoke(f, cast<types>(c), args...); return true; } return false; }() || ...);
};
};
auto data_type_dispatcher = [](auto f) {
return dispatcher_impl<INT, FLOAT, ... other types here ...>(f);
};
The core idea is to wrap the function into a lambda that checks the DataContainer's DataType and calls the function only if it matches. The Fold expression over the || operator is used to unpack the DataTypes.
Usage example:
template<typename T>
void processData(DataContainer<T>& c, int arg) {
if constexpr(std::is_same_v<T, int>) std::cout << "int";
else if constexpr(std::is_same_v<T, float>) std::cout << "float";
std::cout << ", arg: " << arg << '\n';
}
// This needs to be done for each function:
auto pd = data_type_dispatcher([](auto& c, int arg) { processData(c, arg); });
int main() {
DataContainer<float> f;
DataContainer<int> i;
pd(f, 2); // prints float, 2
pd(i, 4); // prints int, 4
}
Full example here.
In order to throw an exception if the type is not supported, simply add a lambda that throws at the end of the fold expression:
([&]{ if(c.GetDataType() == types ) { std::invoke(f, cast<types>(c), args...); return true; } return false; }() || ... || []() -> bool{ throw (std::runtime_error("Type not supported")); }());
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

How can I write a function template that returns either a reference or a value?

I'd like to write a function template that returns either a reference or a value depending on some compile time expression. What I've tried so far is something like this:
template<typename T>
auto&& Func()
{
if constexpr (some_compile_time_expression)
{
return GetReferenceFromSomewhere();
}
else
{
return GetValueFromSomewhere();
}
}
This works fine for all types of references but doesn't work for values. For example, if GetValueFromSomewhere returns a Foo, then the compiler deduces the return type of Func as Foo&& and warns that I'm returning the address of a temporary.
Is there any way to make this work, or am I forced to tease the two branches apart somehow (through function overloads or some such)?
Use decltype(auto) for the return type placeholder, it will preserve the exact value category of the function you're calling in the return statement
template<typename T>
decltype(auto) Func()
{
if constexpr (some_compile_time_expression_dependent_on_T)
{
return GetReferenceFromSomewhere();
}
else
{
return GetValueFromSomewhere();
}
}
Live demo
Pretorian's answer is perfect, but you may also want to learn about std::conditional, which has broader usage. For example, consider a data_ member variable of type int and a member function, that returns data_ either by reference or by value depending on some compile-time condition:
template <bool COND>
std::conditional_t<COND, int&, int> data() { return data_; }
This would not be achievable with decltype(auto). You can also use the same technique to pass arguments to functions by reference/value:
template <bool COND>
void f(std::conditional_t<COND, int&, int> param);
Or, you can switch between copy/move constructors:
class X {
X(std::conditional_t<some_cond, const X&, X&&>) = default;
X(std::conditional_t<some_cond, X&&, const X&>) = delete;
...
};
Etc...

Remove rvalueness, keep lvalue references (standard type trait available?)

I'm trying to write a function that returns a subset of a variadic argument pack under the form of an std::tuple. The function should ideally have no runtime overhead (no unnecessary copies), and it should allow users to access lvalue references and modify them.
Value types, lvalue references and const lvalue references should be maintained. Temporaries (rvalue references), should be "converted" to value types to avoid creating invalid references (references to temporaries).
Example of desired results:
int lr = 5;
const int& clr = lr;
auto t = make_subpack_tuple(lr, clr, 5);
static_assert(is_same
<
decltype(t),
std::tuple<int&, const int&, int>
>{}, "");
// Ok, modifies lr:
std::get<0>(t) = 10;
// Compile-time error, intended:
// std::get<1>(t) = 20;
// Ok, 5 was moved into the tuple:
std::get<2>(t) = 30;
Example incomplete implementation:
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple
<
some_type_trait<decltype(xs)>...
>
(
std::forward<decltype(xs)>(xs)...
);
}
Does what I am trying to do make sense?
Is there a standard type-trait that can be used in place of some_type_trait? Or should I implement my own solution?
The solution for you will be
template<typename... Ts>
auto make_subpack_tuple(Ts&&... xs)
{
return std::tuple<Ts...>(std::forward<Ts>(xs)...);
}
According to template argument deduction rules, the parameter pack Ts... will contain only cv-qualified types and lvalues. The information in this question may be useful too.
I'd just like to chime in that I ran into this same not-really-a-problem ("I think I need to decay rvalue references and keep lvalue references untouched") while implementing an efficient version of Nick Athanasios's foldable Op<operation>. I had had this mess:
template<class Pack, class Op>
struct Foldable
{
mystery_trait_t<Pack> value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(static_cast<std::decay_t<Pack>>(
(op.f)(std::move(value), std::move(rhs.value))
));
}
operator mystery_trait_t<Pack> () && {
return std::move(value);
}
};
template<class Pack>
auto NamedOperator::operator()(Pack&& value) const {
return Foldable<Pack, NamedOperator>(std::forward<Pack>(value), *this);
}
and (after puzzling for a bit, and then starting to ask a SO question, and finding this existing question/answer, and adding a static_assert to my implementation of mystery_trait_t to verify that it was never actually invoked with an rvalue reference type!) it turned out that all I actually needed was
template<class Pack, class Op>
struct Foldable
{
Pack value;
const Op& op;
template<class RhsPack>
auto operator*(const Foldable<RhsPack, Op>& rhs) const {
return op(
(op.f)(std::move(value), std::move(rhs.value))
);
}
operator Pack () && {
return std::move(value);
}
};
(See my whole code on Wandbox.)
This "answer" of mine doesn't contribute any new information, but I thought it would be useful to share, because it just goes to show that even if you think you're way deep in template metaprogramming and are sure you need this "conditional decay" behavior... you really don't need it!
There might be a corollary general rule that writing any_template<T&&> is always a code smell. In Vittorio's original question, he effectively did that twice, although both times it was hidden by decltype syntax:
some_type_trait<decltype(xs)>... // should have been `Ts...`
std::forward<decltype(xs)>(xs)... // could equally well be `std::forward<Ts>(xs)...`