C ++ 14 auto lambda can accept Obj <std :: tuple <void>> - but template functions can't?
Below is a program that fully demonstrates the problem I am seeing.
First, I start with an object that is defined by grouping other types, I started using std :: tuple <> to control the grouping.
template <typename> class object; template <typename... Rs> class object<std::tuple<Rs...> > { }; I assume that these objects can be of type void scattered in the "package". I already know that I cannot "instantiate" a tuple of this type (see Void Type in std :: tuple )
I want to pass these objects, maybe copy / move them ... none of my data members is a tuple of these types. In fact, I can reproduce the problem using the above definition of an empty object.
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” structures are often used in variational recursion, and they are designed to never be created / used. Just group template arguments.
However, I want the signature of the “object” to consist of “user-expected” types / names.
Basically, I experimented with any possible way of passing one of these objects around when std::tuple used to “group” and can only find one way: auto lambdas.
Can anyone explain:
why can an “auto” lambda work for this?
something about template deduction delay? like diff b / w "auto" and "decltype (auto)"?
how to “create” a function parameter to accept one of these objects.
- thanks to all of you for any information about 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 reduced playback:
#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; } std::tuple<void> is the associated class object<std::tuple<void>> , and so in an unqualified call that performs an argument-dependent search, std::tuple<void> is created to look for any friend functions that could be defined in line. This message is causing an error.
An argument-dependent analysis is not performed if the called thing does not name a function or function template; therefore the use of lambda works - takeobj_lambda is an object.
If you use either a qualified call ( ::takeobj(oval) ) or in brackets takeobj ( (takeobj)(oval) ), then compile the code. Both of them disable ADL.