Below is a program that completely demonstrates the problem I'm seeing.
First, I start with an object that is defined using a grouping of other types, I started using a std::tuple<> to manage the grouping.
template <typename> class object;
template <typename... Rs> class object<std::tuple<Rs...> > {
};
I am intending these objects to be capable of having the type void
scattered in the "pack". I am already aware of being unable to "instantiate" a tuple of this type
(see Void type in std::tuple)
I want to pass these objects around, perhaps copy/move them... none of their data members are a tuple of these types. In fact, I can reproduce the problem using the empty object definition above.
I can make it work, using something like:
template <typename... Rs> struct TGrp {};
template <typename> class object;
template <typename... Rs> class object<TGrp<Rs...> > {
};
These types of "grouping" structs are used frequenly in variadic recursion, and they are meant to never get created/used. Just to group template args.
However, I "want" the signature of the 'object' to be made up of "user expected" types/names.
Basically, I was experimenting with any possible way of passing one of these objects around when std::tuple
is used to "group", and could only find one way: auto lambdas.
Can anybody explain:
why the "auto" lambda's can work for this?
something about delayed template deduction? like the diff b/w "auto" and "decltype(auto)"?
how to "design" a function parameter to accept one of these objects.
-- thanks to you all for any insights on this oddity
Example:
#include <tuple>
#include <iostream>
#define GRP std::tuple // IF 'tuple' used: compile error where noted below
//#define GRP TGrp // if THIS is used: all works, and TGrp() is never constructed
// Grouping mechanism
template <typename... Ts> struct TGrp {
TGrp() {
std::cout << "Never printed message\n";
}
};
// MAIN OBJECT (empty for forum question)
template <typename> class object;
template <typename... Rs> class object<GRP<Rs...> > {
};
// Regular function (does NOT work)
void takeobj(object<GRP<void> >& obj) { (void)obj; }
// Lambda - taking anything... (only thing I could make WORK)
auto takeobj_lambda = [](auto obj) { (void)obj; };
// Template func - taking anything (does NOT work)
template <typename T> void takeobj_templ_norm(T obj) { (void)obj; }
template <typename T> void takeobj_templ_clref(const T& obj) { (void)obj; }
template <typename T> void takeobj_templ_lref(T& obj) { (void)obj; }
template <typename T> void takeobj_templ_rref(T&& obj) { (void)obj; }
int main()
{
object<GRP<void> > oval;
//takeobj(oval); // <-- causes compile error
takeobj_lambda(oval); // works
//takeobj_templ_norm(oval); // <-- also error
//takeobj_templ_clref(oval); // <-- also error
//takeobj_templ_lref(oval); // <-- also error
//takeobj_templ_rref(oval); // <-- also error
return 0;
}
Edit: adding a trimmed down reproduction:
#include <tuple>
// MAIN OBJECT (empty for forum question)
template <typename> class object;
template <typename... Rs> class object<std::tuple<Rs...> > {
};
// Regular function (does NOT work)
void takeobj(object<std::tuple<void> >& obj) { (void)obj; }
// Lambda - taking anything... (only thing I could make WORK)
auto takeobj_lambda = [](auto obj) { (void)obj; };
int main()
{
object<std::tuple<void> > oval;
//takeobj(oval); // <-- causes compile error
takeobj_lambda(oval); // works
return 0;
}