std::bind
и std::thread
разделяют несколько принципов проектирования. Поскольку оба из них хранят локальные объекты, соответствующие переданным аргументам, нам нужно использовать либо std::ref
, либо std::cref
, если желательна эталонная семантика:
void f(int& i, double d) { /*...*/ }
void g() {
int x = 10;
std::bind(f, std::ref(x), _1) (3.14);
std::thread t1(f, std::ref(x), 3.14);
//...
}
Но я заинтригован недавним личным открытием: std::bind
позволит вам передать значение в приведенном выше случае, хотя это не то, что обычно требуется.
std::bind(f, x, _1) (3.14); // Usually wrong, but valid.
Однако это не относится к std::thread
. Следующее приведет к ошибке компиляции.
std::thread t2(f, x, 3.14); // Usually wrong and invalid: Error!
На первый взгляд я думал, что это ошибка компилятора, но ошибка действительно законна. Похоже, что шаблонная версия конструктора std::thread
не может правильно выводить аргументы из-за copy decaying require (tranforming int&
in int
), наложенным 30.3.1.2.
Возникает вопрос: почему бы не потребовать что-то похожее на аргументы std::bind
? Или это подразумеваемая очевидная несогласованность?
Примечание. Объяснено, почему это не дублируется в комментарии ниже.