Как отмечает @ JDługosz в комментариях, Херб дает другие советы в другом (позже?) разговоре, см. примерно отсюда: https://youtu.be/xnqTKD8uD64?t=54m50s .
Его совет сводится только к использованию параметров значения для функции f
, которая принимает так называемые аргументы стока, предполагая, что вы переместите конструкцию из этих аргументов приемника.
Этот общий подход только добавляет накладные расходы конструктора перемещения для аргументов lvalue и rvalue по сравнению с оптимальной реализацией f
с учетом значений lvalue и rvalue соответственно. Чтобы понять, почему это так, предположим, что f
принимает параметр значения, где T
- это некоторая копия и перемещение конструктивного типа:
void f(T x) {
T y{std::move(x)};
}
Вызов f
с аргументом lvalue приведет к конструктор копирования, вызываемый для построения x
, и конструктор перемещения, вызываемый для построения y
. С другой стороны, вызов f
с аргументом rvalue приведет к вызову конструктора перемещения для построения x
и другого конструктора перемещения, который будет вызываться для построения y
.
В общем, оптимальная реализация f
для аргументов lvalue выглядит следующим образом:
void f(const T& x) {
T y{x};
}
В этом случае для построения y
вызывается только один конструктор копирования. Оптимальная реализация f
для аргументов rvalue, опять-таки, в общем случае выглядит следующим образом:
void f(T&& x) {
T y{std::move(x)};
}
В этом случае для построения y
вызывается только один конструктор перемещения.
Таким образом, разумный компромисс заключается в том, чтобы взять параметр значения и иметь один дополнительный вызов конструктора для аргументов lvalue или rvalue относительно оптимальной реализации, что также является советом, данным в разговоре Херба.
As @ JDługosz отметил в комментариях, передача по значению имеет смысл только для функций, которые будут строить какой-либо объект из аргумента приемника. Когда у вас есть функция f
, которая копирует свой аргумент, подход с поправкой будет иметь дополнительные накладные расходы, чем общий метод pass-by-const-reference. Метод pass-by-value для функции f
, сохраняющий копию его параметра, будет иметь следующий вид:
void f(T x) {
T y{...};
...
y = std::move(x);
}
В этом случае есть построение копии и назначение перемещения для аргумент lvalue и конструкцию перемещения и назначение перемещения для аргумента rvalue. Наиболее оптимальным аргументом для аргумента lvalue является:
void f(const T& x) {
T y{...};
...
y = x;
}
Это сводится только к заданию, которое потенциально намного дешевле, чем конструктор копирования, плюс назначение перемещения, требуемое для подхода с переходом по значению. Причина этого заключается в том, что назначение может повторно использовать существующую выделенную память в y
и, следовательно, предотвращать (де) распределения, тогда как конструктор копирования обычно выделяет память.
Для аргумента rvalue наиболее оптимальная реализация для f
, который сохраняет копию, имеет вид:
void f(T&& x) {
T y{...};
...
y = std::move(x);
}
Таким образом, в этом случае назначается только перемещение. Передача rvalue в версию f
, которая принимает ссылку const, стоит только присваивание вместо назначения перемещения. Так, условно говоря, предпочтительнее вариант f
, принимающий const-ссылку в этом случае как общую реализацию.
Итак, в общем случае для наиболее оптимальной реализации вам нужно будет перегрузить или сделать что-то вроде идеальной пересылки, как показано в разговоре. Недостатком является комбинаторный взрыв в количестве требуемых перегрузок, в зависимости от количества параметров для f
, если вы решите перегрузить класс значений аргумента. Идеальная пересылка имеет тот недостаток, что f
становится функцией шаблона, которая препятствует ее созданию в виртуальном режиме и приводит к значительно более сложному коду, если вы хотите получить его на 100% вправо (см. Разговор для деталей gory).
Вы можете создать объект JavaScript Date
, передав значения year, month, day
. Обратите внимание, что вам нужно -1
из месяца, потому что месяцы, как и большинство вещей в JavaScript, начинаются с 0
. (January = 0, December = 11
)
Когда у вас есть дата, вы можете использовать Date.toLocaleString()
, что позволяет вам передавать объект options
с вашими предпочтениями форматирования.
$("#btnGetDate").on("click", function() {
//Get values from the inputs
var year = $("#txtYear").val();
var month = $("#ddlMonth").val();
var day = $("#txtDay").val();
//Format the date and output it
var formattedDate = formatDate(year, month, day);
console.log(`Your date is ${formattedDate}`);
});
function formatDate(year, month, day) {
//Create a Date object using the values
var date = new Date(year, month - 1, day);
//Define how you want the date to be formatted
var options = {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric"
};
//Format the date according to our options
return date.toLocaleDateString("en-US", options);
}
input,select {margin-right: 10px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Month
<select id="ddlMonth">
<option value="01">January</option>
<option value="02">February</option>
<option value="03">March</option>
<!-- and so on... -->
</select>
Day
<input id="txtDay" type="number" placeholder="dd">
Year
<input id="txtYear" type="number" placeholder="yyyy">
<button id="btnGetDate">Output Date</button>
Конечно, это может использовать некоторые ограждения / проверки правильности ввода неправильных дат, ввода дня или года в неправильном формате и т. д., но я оставлю эту часть на ваше усмотрение!