7

I'm looking for a unary functor which will dereference it's argument and return the result. Of course I can write one, it just seemed like something should already exist.

So given the code:

const auto vals = { 0, 1, 2, 3 };
vector<const int*> test(size(vals), nullptr);

iota(begin(test), end(test), data(vals));

transform(cbegin(test), cend(test), ostream_iterator<int>(cout, " "), [](const auto& i){ return *i; });

Live Example

I was hoping that there was a functor that I could use instead of the lambda. Does such a thing exist, or do I need to just use the lambda?

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 2
    I found very probable answer on why the functionality wasn't added to `std` [here](http://forums.codeguru.com/showthread.php?495892-std-dereference-and-std-reference&p=1933466#post1933466) – W.F. Jan 05 '17 at 14:39
  • @W.F. It's interesting, I actually read through that post before asking the question. The example I've given is an MCVE, [my actual use case for this](http://stackoverflow.com/a/41486541/2642059) *is* a `vector::const_iterator>` :( – Jonathan Mee Jan 05 '17 at 15:33

1 Answers1

9

Assuming that by "functor" you mean "function object" or "callable object", there doesn't seem to be what you desire in the Standard Library.

It is trivial to implement it yourself:

struct deferencer
{
    template <typename T>
    decltype(auto) operator()(T&& x) const
        noexcept(noexcept(*x))
    { 
        return *x; 
    }
};

Note that your lambda doesn't do what you expect, as its implicit return type is -> auto, which makes a copy. One possible correct lambda is:

[](const auto& i) -> decltype(auto) { return *i; }

If you don't specify an explicit trailing return type for a lambda, the implicit one will be auto which is always a copy. It doesn't matter if operator* returns a reference, since the lambda returns a copy (i.e. the reference returned by operator* is then copied by the lambda's return statement).

struct A
{
    A() = default;
    A(const A&) { puts("copy ctor\n"); }
};

int main()
{
    []{ return *(new A); }(); // prints "copy ctor"
}

wandbox example

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • 3
    I would use `decltype(auto)` so it also works for InputIterators that return proxy objects – Jonathan Wakely Jan 05 '17 at 14:42
  • @JonathanWakely: good point, updating the code to make it more general. – Vittorio Romeo Jan 05 '17 at 14:43
  • @JonathanWakley What am I missing here? I thought the [built-in indirection operator](http://en.cppreference.com/w/cpp/language/operator_member_access#Built-in_indirection_operator) returned a reference to the value. Why would this be returning by value? – Jonathan Mee Jan 05 '17 at 15:42
  • @JonathanMee: [`operator*` can be overloaded to return something that's not a reference](http://melpon.org/wandbox/permlink/8dDp82Icz0COtBeb). It could be useful if you want to return something that looks like a reference but is actually a proxy object. – Vittorio Romeo Jan 05 '17 at 15:56
  • @VittorioRomeo Fair enough, but I believe this statement is in error: "Your lambda doesn't do what you expect, as its implicit return type is -> auto, which makes a copy." As I understand it, in the general case it should return a by reference, because for non-overloaded indirection operators the return type is a reference. – Jonathan Mee Jan 05 '17 at 16:03
  • 1
    @JonathanMee: if you don't specify an explicit *trailing return type* for a lambda, the implicit one will be `auto` which is **always a copy**. It doesn't matter if `operator*` returns a reference, since the lambda returns a copy *(i.e. the reference returned by `operator*` is then copied by the lambda's `return` statement)*. [**wandbox example**](http://melpon.org/wandbox/permlink/Sa54KJuA2R3EtFMy) – Vittorio Romeo Jan 05 '17 at 16:06
  • @VittorioRomeo "error: expected unqualified-id before '=' token" doesn't seem like a great way to prove your point? – Jonathan Mee Jan 05 '17 at 16:09
  • @JonathanMee: come on, just give the lambda a name - I shared the wrong version of the code. Fixing... – Vittorio Romeo Jan 05 '17 at 16:12
  • @VittorioRomeo Well before I refreshed the page, I'd typed up a question on why the return of a lambda was copying. If you want to elaborate on why, "the implicit one will be `auto` which is always a copy." I'd appreciate you doing so here: http://stackoverflow.com/q/41505807/2642059 – Jonathan Mee Jan 06 '17 at 12:34
  • 1
    @JonathanMee: my remark about the return type of the lambda was not really related to the original question. I just wanted to make you notice a potential error in your code/understanding of the language. As you can see, the [question has already been asked and properly answered in the past](http://stackoverflow.com/questions/29610318/what-is-the-return-type-of-a-lambda-expression-if-an-item-of-a-vector-is-returne). – Vittorio Romeo Jan 06 '17 at 12:52
  • @VittorioRomeo Yup, and I appreciated you pointing it out to me. I simply didn't understand. – Jonathan Mee Jan 06 '17 at 12:57
  • @JonathanWakely So how does `decltype(auto)` get translated as `int&` when `auto` would have stripped the reference? – Jonathan Mee Jan 06 '17 at 12:59
  • 2
    See [`auto`, **(5)**](http://en.cppreference.com/w/cpp/language/auto), which directs you to the [rules for `decltype`](http://en.cppreference.com/w/cpp/language/decltype). In short, `decltype(x)` preserves the "referenceness" of the `x` expression. – Vittorio Romeo Jan 06 '17 at 13:02
  • @JonathanMee because that's what `decltype(auto)` means. – Jonathan Wakely Jan 06 '17 at 13:33