18

I have a traditional C lib and a function (setsockopts) wants an argument by pointer. In C++11 (gcc 4.8), can I pass this argument without initializing a named variable?

I have the following, non-satisfying solution:

#include <iostream>
#include <memory>

int deref(int const * p) {return * p;}

using namespace std;

int main() {
    int arg = 0; cout << deref(& arg) << endl;
    // works, but is ugly (unnecessary identifier)

    cout << deref(& 42) << endl;
    // error: lvalue required as unary ‘&’ operand

    cout << deref(& * unique_ptr<int>(new int(42))) << endl;
    // works, but looks ugly and allocates on heap
}
Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
not-a-user
  • 4,088
  • 3
  • 21
  • 37

3 Answers3

24

I'd just create a wrapper to setsockopt if that's really a trouble (not tested)

template <typename T>
int setsockopt(int socket, int level, int optname, const T& value) {
    return setsockopt(socket, level, optname, &value, sizeof(value));
}

...

setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, 1);
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
20

Write a function template to convert rvalues to lvalues:

template<typename T>
T &as_lvalue(T &&val) {
    return val;
}

Now, use it:

deref(&as_lvalue(42));

Warning: this doesn't extend the lifetime of the temporary, so you mustn't use the returned reference after the end of the full-expression in which the temporary was created.

Mankarse
  • 39,818
  • 11
  • 97
  • 141
  • As exemplified in [another answer](http://stackoverflow.com/a/23567005/464581) a function template that does this, and additionally also applies the `&` operator for you, and even peeks beneath any user override of that operator, already exists in the standard library... – Cheers and hth. - Alf May 09 '14 at 15:14
  • 2
    @Cheersandhth.-Alf except that bypasses `operator&` overloading, and we wouldn't want to do that would we? – Yakk - Adam Nevraumont May 09 '14 at 15:20
  • @Yakk: bypassing overloading of `operator&` is precisely what I would want to do. and what this answer fails to do. don't know about you (plural). – Cheers and hth. - Alf May 09 '14 at 18:45
10

You can bind a const reference to a temporary:

cout << deref(addressof<const int>(42)) << endl;
ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • 1
    Huh. Isn’t that arguably a bug in `addressof` (i.e. it should probably ensure that it’s called with an lvalue)? – Konrad Rudolph May 09 '14 at 14:30
  • @KonradRudolph you might be right; `reference_wrapper` etc. have deleted rvalue reference overloads. It should probably be possible for `addressof` to do the same. – ecatmur May 09 '14 at 14:37
  • @KonradRudolph: why should it not support rvalues – Cheers and hth. - Alf May 09 '14 at 14:39
  • +1 i hadn't registered that `addressof` had migrated from boost to c++11 thanks – Cheers and hth. - Alf May 09 '14 at 14:39
  • 1
    @Cheers: For the same reason `&` doesn't support lvalues -- very easy to create pointers to dead stuff. – Billy ONeal May 09 '14 at 14:42
  • @BillyONeal: I'm not so sure "pointers to dead stuff" was part of the C rationale for limiting the built-in `&` to lvalues. Rather, I think it was about C as a portable assembly language with the programmer in full control, where as little as possible (such as allocation of a variable) should be implicit and automatic. I'm talking here about the initial design goal and use of C to help port Unix to more platforms. That said, I also disagree that `addressof` would be safer with such a restriction. C++ programmers have to handle limited nested lifetimes all the time, no problem. – Cheers and hth. - Alf May 09 '14 at 15:10
  • 2
    @Cheers “C++ programmers have to handle limited nested lifetimes all the time, no problem.” – “No problem”? I’d claim that it’s one of the (if not *the*) biggest sources of bugs in modern C++. – Konrad Rudolph May 09 '14 at 15:52
  • @Cheers: That doesn't make any sense. When you use a constant in C, a variable comes into play on the underlying machine. C is quite happy to construct as many rvalues or aggregates as you want inside of an expression; if they really wanted to prevent all implicit behavior like this they wouldn't have allowed that either. – Billy ONeal May 09 '14 at 16:38
  • @BillyONeal: this is incorrect: "When you use a constant in C, a variable comes into play on the underlying machine". often constants exist only in the machine code instructions. often results of rvalue expressions exist only in non-adressable processor registers. does it make more sense now? – Cheers and hth. - Alf May 09 '14 at 18:48
  • 1
    I am sure it would be helpful to also show the core-language way to write this `deref(&(const int&)0);`. – Johannes Schaub - litb May 09 '14 at 18:57
  • @Johannes Schaub - litb properly that's a `static_cast`. But `addressof` is still required in the most general case. – ecatmur May 09 '14 at 19:06
  • @ecatmur there is no argument about the better generality of `addressof` here. It is merely useful to point out (as I did) that there's also a core language way to get a pointer to an `int` using a cast. I don't know what you mean by "properly that's a static_cast" though. It sounds like my cast is unproper, but I think it's fine. It's actually equivalent to a "static_cast". Matter of taste what to use, basically. Or did you mean to write "probably that's a static_cast"? If so, then yes, I can confirm. – Johannes Schaub - litb May 09 '14 at 19:26
  • @JohannesSchaub-litb I just wanted to clarify that `const_cast` and `reinterpret_cast` are not required. With a C-style cast there's the risk of invoking a more powerful cast than intended. – ecatmur May 09 '14 at 19:34
  • @Cheers: Whether the variable is in the machine code or on the stack is irrelevant. You can create a pointer to either place. To the machine there is no difference. – Billy ONeal May 09 '14 at 19:35
  • @BillyONeal: no, there is in general no such thing as a variable in the machine code, and no, you cannot in general create a pointer to the representation of a constant in machine code. for one it doesn't need to be explicitly represented as a separate pattern. secondly, if it is, it isn't necessary stored in full bytes or even consecutive ones. in short you don't know what you're talking about and you should have understood that already with my previous comment. continuing to make unrealistic assertions after that is just argumentative. – Cheers and hth. - Alf May 09 '14 at 19:51
  • @Cheers: On any Von Neumann machine, you can certainly create pointers to anything in machine code. As far as the machine is concerned memory is memory is memory. I'm not the one making the "unrealistic assertion" that C disallows taking the address of a temporary because the temporary would need to be stored somewhere. – Billy ONeal May 09 '14 at 21:08
  • 4
    I hope readers understand that nothing Billy has said so far has been technically meaningful, and that by now there is no chance that that is due to any misunderstanding. – Cheers and hth. - Alf May 09 '14 at 21:19
  • This didn't work for me because in later C++ compilers the template method is "deleted". It seems that compiler is trying very very hard to make me use an explicit temporary variable, so I listened to the compiler and it is fine. I suggest this unless you absolutely cannot. – Wheezil Aug 01 '18 at 22:17