On 11/15/17 6:46 AM, Jonathan M Davis wrote:
On Wednesday, November 15, 2017 09:49:56 helxi via Digitalmars-d-learn
wrote:
On Wednesday, 15 November 2017 at 09:34:32 UTC, helxi wrote:
On Wednesday, 15 November 2017 at 09:23:53 UTC, Jonathan M

Davis wrote:
On Wednesday, November 15, 2017 09:04:50 helxi via

Digitalmars-d-learn wrote:
Hi. What function signature should I use for receiving a
constant
reference of an r/l value object? Is it auto fn(inout ref
const
myClass obj)?
I want to:
1. Take a constant reference of the object, not copy them
2. The object itself may be const or non const.

ref const(Type) would be the const version of ref Type. e.g.

auto foo(ref const(int) i) {...}

- Jonathan M Davis

Thanks. Just a couple of follow-ups:
1. I've never seen a signature like `const(int)`is the
enclosing parenthesis around the `int` necessary?

In this case, no. Without parens, the entire type is const; with parens,
only the part in parens is const - e.g. const(int)* would be a pointer to a
const int, whereas const int* or const(int*) would be a const pointer to a
const int.

2. What effects does prefixing the arguments with `inout` have?
For example:  fn(inout ref const string str){...}

Combining inout and const is pretty meaningless. Arguably, it's stupid of
the compiler to even allow it. inout makes it so that the constness of the
return type is based on the constness of the parameter but treats the
parameter as const within the function. But if you also mark the parameter
with const, then it really is const.

Terribly sorry for my bad choice of words. Basically I want to
utilize D's "inout" to avoid writing two functions like this:

#include <iostream>
#include <string>

void fn(std::string& str) {
    std::cout << str << " called from fn(std::string& str)"
              << "\n ";
}

void fn(const std::string& str) {
    std::cout << str << " alled from fn(const std::string& str)"
              << "\n";
}

int main() {
    fn("Test 1");
    std::string b = "test";
    b += " 2";
    fn(b);
}

A few things here:

1. you do not need to take D strings by reference, they are simply a pointer and length. Unlike C++ where accepting a std::string by value will make a copy of the string, that does not happen in D. 2. inout doesn't work like a template. So it's not clear from your examples that even if you used inout you would get what you want.

So I would recommend this:

void fn(const(char)[] str) { ... }

Which will handle all cases, rvalues, lvalues, etc. And it won't be expensive, ever.

That is, unless you actually *want* to mutate lvalues :) Then you do have to write 2 functions, and I can't see how you avoid that.

The only real reason to use inout is if you need the return type is if you
need the return type's constness to match the argument. So,

inout(SomeType) foo(ref inout Type t) {...}

works (the return type type doesn't need to match, but its constness will
match the constness of the argument). But you need a return type for that to
work, so your void function example couldn't be inout.

This is not entirely true. There is one good reason to use inout on a parameter without having a return value, and that is the double-indirection problem.

For example:

void foo(ref const(int)* x)
void foo2(ref inout(int)* x)

int *p;
foo(p); // error.
foo2(p); // ok

-Steve

Reply via email to