), но вы все еще загромождаете вывод ошибок несущественными вещами. Используя эталонную версию, вы избегаете рассматривать копии в целом и сосредотачиваетесь только на том, что на самом деле имеете в виду.
могу определить шаблон функции, чтобы предотвратить неявные преобразования?
Кажется, я могу предотвратить неявные преобразования, используя не шаблонные функции, но не используя шаблоны функций.
Определение шаблона функции переадресации как= delete
слишком агрессивен, поскольку предотвращает вызов с неконстантными ссылками lvalue.
Определение шаблона функции с аргументом const rvalue как=delete
[1] не предотвращает неявные преобразования.
Определение перегрузки rvalue для определенного типа как=delete
работает, но я хотел бы сделать это с помощью шаблонов.
Пример минимального кода:
struct A {};
struct B {
B() = default;
B(const A&) {}
};
// Delete const rvalue reference.
template <class T>
void t_no_rvalue(const T&&) = delete; // 1
void t_no_rvalue(const B&) {} // 2
// Delete forwarding reference.
template <class T>
void t_no_fwd_ref(T&&) = delete; // 3
void t_no_fwd_ref(const B&) {} // 4
// (non-template) Delete const rvalue reference.
void no_rvalue(const B&&) = delete; // 5
void no_rvalue(const B&) {} // 6
int main(int argc, char* argv[]) {
A a;
B b;
// Undesired behaviour, implicit conversion allowed.
t_no_rvalue(a); // resolves to 2
t_no_rvalue(b); // resolves to 2
// Undesired behaviour, invocation with non-const reference disallowed.
t_no_fwd_ref(a); // resolves to 3
t_no_fwd_ref(b); // resolves to 3
// Desired behaviour.
no_rvalue(a); // resolves to 5
no_rvalue(b); // resolves to 6
}
Мой реальный пример использования - хэширование вариантов, когда неявное преобразование подтипа варианта обратно в тип, подобный варианту, вызовет бесконечную рекурсию, если хеш-функция не специализирована для всех компонентов варианта. Приведенный выше пример кода понятнее.
[1] Попытка вПочему я могу предотвратить неявные преобразования для примитивов, но не для пользовательских типов? но с неработающим примером кода.