0

I'm writing a wrapper class for a class of type inner_t. Can I call the proper constructor (lvalue reference or rvalue reference) for the inner class in the following way?

template<typename S, typename T>
struct u_ref {
};

template<typename S>
struct u_ref<S, const S&> {
    typedef const S& type;
};

template<typename S>
struct u_ref<S, S&&> {
    typedef S&& type;
};

class wrapper_t {
private:
    inner_t data;
public:
    template<typename T>
    wrapper_t(typename u_ref<inner_t,T>::type c_data):
        data(std::forward(c_data)) {
    }
}
dspyz
  • 5,280
  • 2
  • 25
  • 63
  • Why so complicated? Just use variadics, enable_if and forwarding? – Kerrek SB Dec 31 '13 at 00:34
  • I don't know how to use any of that stuff and I can't find any good tutorials. Can you show me? – dspyz Dec 31 '13 at 00:34
  • At the risk of being the hundredth duplicate... – Kerrek SB Dec 31 '13 at 00:35
  • Also, I want to be able to re-use u_ref. What I'm really not sure about is whether the correct type will be bound. And even if this looks like it works, I don't know if the correct type is being bound, and I don't know whether I've invoked undefined behavior anywhere. I don't know the rules, I'm just trying to imitate what it looks like other people do – dspyz Dec 31 '13 at 00:36
  • Please don't do that. Take the extra week out and learn the rules. You can't become good at C++ by stabbing into the dark until you hit something squishy. You have to boldly go forward, eyes open. – Kerrek SB Dec 31 '13 at 00:44
  • From where? Where do I learn the rules? There doesn't seem to be any good sources – dspyz Dec 31 '13 at 00:44
  • (At least not any C++11 compatible ones) – dspyz Dec 31 '13 at 00:45
  • Have you looked at the ["recommended books" section](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) on this site? Mix in [Bjarne's C++11 FAQ](http://www.stroustrup.com/C++11FAQ.html), [Scott Meyer's ebook](http://www.artima.com/shop/overview_of_the_new_cpp), and fill up the remaining gaps by watching Stack Overflow. – Kerrek SB Dec 31 '13 at 00:45
  • Yes, all the template-related ones are pre-C++11 – dspyz Dec 31 '13 at 00:46
  • For the moment, can someone just tell me yes/no if this does what I think it does? – dspyz Dec 31 '13 at 00:49
  • Most of these techniques aren't specific to C++11 anyway. There are only small changes that make it in, like rvalue references. – Kerrek SB Dec 31 '13 at 00:50
  • Yes, but this question is all about rvalue references so I can guess right off the bat that reading any of those template books won't answer it – dspyz Dec 31 '13 at 00:51
  • But half the stuff you said was new to you was completely classic C++98. The point is, if you build up a solid foundation of C++98, you won't be thrown off by the few new things. – Kerrek SB Dec 31 '13 at 00:56
  • So, you're suggesting I read one of the C++98 template books and then read one of the C++ 11 (non-template) books, and from there I'll be able to piece together how to solve these sorts of problems. Is that how you learned it? – dspyz Dec 31 '13 at 00:58
  • Yes, that's what I'm suggesting. Traits and templaty stuff in particular has a long tradition. I didn't learn anything in a structured way, I just pick something that excites me and keep digging until I understand it. It appears that this has eventually led me to some degree of understanding of C++; but then again, I'm the kind of person who keeps a copy of the standard on their mobile phone... – Kerrek SB Dec 31 '13 at 00:59
  • 1
    After more browsing, I just found this: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ This is the real answer I was looking for. It's simple and makes sense to me and I don't need any templates at all. – dspyz Dec 31 '13 at 01:20

2 Answers2

2

The standard idiom is this:

Baby's first template:

#include <utility>

struct Foo
{
    Inner child;

    template <typename ...Args>
    Foo(Args &&... args) : child(std::forward<Args>(args)...) { }

    // ...
};

Grown-up version: The problem with the above is that it makes Foo constructible from anything, which is unclean. We must disable overloads that don't make sense.

#include <type_traits>
#include <utility>

struct Foo
{
    Inner child;

    template <typename ...Args,
              typename = typename std::enable_if<std::is_constructible<Inner, Args...>::value>::type>
    Foo(Args &&... args) : child(std::forward<Args>(args)...) { }

    // ...
};

In this manner, the trait std::is_constructible<Foo, Args...> will have the exact same values as std::constructible<Inner, Args...>, rather than being true for everything.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • What does typename = typename mean? I haven't seen '=' in a template declaration before? – dspyz Dec 31 '13 at 00:38
  • @dspyz: It's a defaulted, unnamed template argument. – Kerrek SB Dec 31 '13 at 00:39
  • Could you point me to something that describes things you can do with templates including the '='? (I've asked this a couple times in a couple ways, but nobody seems to have post-C++11 answers) – dspyz Dec 31 '13 at 00:40
  • @dspyz: It's just a default argument. Think about how you use `std::vector`. You never spell out the second argument. Why is that? (And Stroustrup's Rule strikes again: You really only need to understand `int` and `std::vector` to understand C++.) – Kerrek SB Dec 31 '13 at 00:42
  • Yes, I understand that now. But it always seems like I ask questions like this on SO and someone comes up with a construct or a notation I've never seen or heard of before. I want to know where's the big standard book I can learn about all these things in so I don't have to rely so heavily on SO. – dspyz Dec 31 '13 at 00:43
0

After much search, I found this: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Rather than explicitly invoking the copy constructor, I can get the same result much more simply using pass-by-value:

class wrapper_t {
private:
    inner_t data;
public:
    wrapper_t(inner_t c_data):
        data(std::move(c_data)) {
    }
}
dspyz
  • 5,280
  • 2
  • 25
  • 63
  • 3
    It might be noteworthy that this potentially invokes two move-constructions. Constructions from an rvalue (move-constructions) aren't free, for example if part of the object cannot be moved but must be copied. Your original question OTOH used something similar to perfect forwarding, which does not invoke any unnecessary copy- or move-operations (besides conversions, like `push_back` vs `emplace_back`). – dyp Dec 31 '13 at 01:53