Prev: Current time based on a timezone?
Next: Distinguish between pointers created with 'new' and created with references.
From: bf on 15 Jul 2010 08:47 On Jul 14, 5:48 pm, bf <bjor...(a)fahller.se> wrote: > I think a solution can be made with a variadic template constructor, > which also nicely takes care of multi-parameter constructors, but I > fail to figure out how to do a std::forward<U...>(u...). Suggestions? I just figured out a (the?) solution: template <typename T> class wrapper { public: template <typename ...U> wrapper(U&& ...u) : t(std::forward<U>(u)...) {} private: T t; }; Works for any number of parameters that the contructor of T can accept. _ /Bjorn -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: SG on 15 Jul 2010 08:47 On 14 Jul., 17:48, bf wrote: > Suppose I need a template that encapsulates an object, and I need the > ability to construct the template instantiations in all the ways that > the encapsulated object can be constructed. A possible construction > may be: > > template <typename T> > class wrapped > { > public: > wrapped() {} > template <typename U> > wrapped(U&& u) : t(std::forward<U>(u) {} > private: > T t; > }; > > Unfortunately it fails if T isn't default constructible. > [...] > I think a solution can be made with a variadic template constructor, > which also nicely takes care of multi-parameter constructors, but I > fail to figure out how to do a std::forward<U...>(u...). Suggestions? template <typename T> class wrapped { public: template <typename... U> explicit wrapped(U&&... u) : t(std::forward<U>(u)...) {} private: T t; }; I'm not 100% sure if it handles the default construction case but I think it does. Cheers! SG -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: lucdanton on 15 Jul 2010 08:47 On Jul 14, 5:48 pm, bf <bjor...(a)fahller.se> wrote: > QOI detail, or behaviour mandated by proposed standard > wording? I ask myself that sort of question quite often. I'm not sure what the answer when side-effects are present in either the constructor(s) and destructor. Obviously under the as-if rule an implementation is free to sort those details out but from what I know of compiler technology and static analysis this can be tricky for non-trivial constructors/ destructors. > I think a solution can be made with a variadic template constructor, > which also nicely takes care of multi-parameter constructors, but I > fail to figure out how to do a std::forward<U...>(u...). Suggestions? I typically write a perfect forwarding constructor thus: template<typename ...U> some_type(U&& ...u): some_member(std::forward<U>(u)...) {} Which is, incidentally, what appears in papers for the next standard I believe. The trick (well, for me anyway) is to write as if the template were not variadic, and adding ...'s in such a fashion that it is factored out the furthest. My latest attempt was "variading" the following: template<typename T> struct { boost::variant< std::future<T>*, T > f; }; to: template<typename ...T> struct { boost::variant< std::future<T>*, T ...> f; }; Note also that under gcc-4.5 a variadic, perfect-forwarding constructor will mess copy construction two-fold: - a custom-defined constructor suppress the default instantiation of the copy constructor This is obvious but if you forget it you might not notice it if the perfectly-forwarded call is valid construct! The obvious cure is adding the default copy constructor: some_type(some_type const&) = default; (you can put in delete instead if your type is non-copyable and you want a more explicit warning when someone attempts to copy) - the perfect-forwarding constructor eats reference to non-const. D'oh ! So assuming you do have a copy constructor: some_type s; auto const& cr = s; some_type(cr); // fine! some_type(s); // Uh oh! some_type(U&& ...u) gets called with U = some_typ&! I don't know if this is intended by the standard or a quirk of gcc-4.5 (rvalue refs 1.0 got redesigned for this kind of gotcha's I believe, but much worse). I've had some luck disabling that sort of behaviour with std::enable_if and std::is_same (from <type_traits>) but I'm not that familiar with template metaprogramming so I don't think I've done it for _variadic_ perfect-forwarding constructors. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Johannes Schaub (litb) on 16 Jul 2010 01:18 bf wrote: > Unfortunately it fails if T isn't default constructible. A possible > solution can be made by defaulting the template parameter, instead of > an explicit default constructor. > > template <typename T> > class wrapped > { > public: > template <typename U = T> > wrapped(U&& u = U()) : t(std::forward<U>(u) {} > private: > T t; > }; > > This allows default construction if T supports it, so logically it > works. In my experiments with g++, however, I see that the defaulted > value isn't optimized away. The move constructor for T is presumably > cheap, so it's probably not the end of the world, but it's > unnecessary. QOI detail, or behaviour mandated by proposed standard > wording? > > I think a solution can be made with a variadic template constructor, > which also nicely takes care of multi-parameter constructors, but I > fail to figure out how to do a std::forward<U...>(u...). Suggestions? > _ Notice that a simple variadic constructor has bad behavior for overload resolution: void f(wrapped<int>); void f(string); // eww, ambiguous! int main() { f("foo"); } For inheriting constructors, this problem is solved by saying "using base::base;". For forwarding data member constructors, you can use SFINAE template <typename T> class wrapped { public: template <typename ...U, typename = bool[is_constructible<T, U...>::value]> wrapped(U&& ...u) : t(std::forward<U>(u)...) {} private: T t; }; This still isn't perfect, as the following example shows: void f(wrapped< vector<string> >); void f(wrapped<int>); int main() { f(42); } // ambiguous! The "wrapped" constructor template is non-explicit, thus being available both times and not SFINAE'ed out because vector has an explicit ctor taking an int. is_constructible tells us that it will work. Of course if you were to use it unwrapped, you could call "f" fine. Not only because 42 -> int would be an exact match, but because "42 -> vector<string>" wouldn't be possible in the first place. If you aim for equivalence to the non-wrapped case, you have to simulate copy-initialization and direct initialization distinction (explicit and non- explicit constructors). I don't know whether that's possible at all. But i can't see a real pressing need right now. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: SG on 17 Jul 2010 07:27 On 16 Jul., 01:47, lucdantonwrote: > > Note also that under gcc-4.5 a variadic, perfect-forwarding > constructor will mess copy construction two-fold: > > - a custom-defined constructor suppress the default instantiation of > the copy constructor No, that doesn't sound right. A constructor template is never considered a copy constructor (see �12.8/2). If no copy constructor has been declared a copy constructor is declared implicitly (see �12.8/4). Any user-defined constructor disables the implicit generation of a default constructor. So, that's maybe what you were thinking of. > This is obvious but if you forget it you might not notice it if the > perfectly-forwarded call is valid construct! I'm not following you. > The obvious cure is adding the default copy constructor: I don't see why this is supposed to be necessary. > - the perfect-forwarding constructor eats reference to non-const. > D'oh ! > So assuming you do have a copy constructor: > some_type s; > auto const& cr = s; > some_type(cr); // fine! > some_type(s); // Uh oh! some_type(U&& ...u) gets called with U = > some_typ&! > > I don't know if this is intended by the standard or a quirk of gcc-4.5 > (rvalue refs 1.0 got redesigned for this kind of gotcha's I believe, > but much worse). As far as I can tell this follows from the overload resolution rules. > I've had some luck disabling that sort of behaviour > with std::enable_if and std::is_same (from <type_traits>) but I'm not > that familiar with template metaprogramming so I don't think I've done > it for _variadic_ perfect-forwarding constructors. I can think of two approaches to handle this situation. (1) Offer both copy constructors (one taking ref-to-const and another taking a ref-to-non-const) (2) Split the variadic contructor template into two templates: one handling a single argument and another handling two or more arguments. The first one would use SFINAE to disable the U=some_type& case. Cheers! SG -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: Current time based on a timezone? Next: Distinguish between pointers created with 'new' and created with references. |