Контекст
При передаче аргументов функциям мы можем либо передать по ссылке , либо передать по значению .
One Преимущество передачи по ссылке заключается в том, что аргумент не нужно реализовывать с помощью его собственной копии, и это может показаться выгодным для пользовательских объектов, которые содержат много данных.
Но для интерфейсов нескольких классов создание Функция передачи по ссылке для каждого интерфейса может быть… неопрятной, например:
void parse(Console&);
void parse(Dialog&);
void parse(Image&);
void parse(Window&);
void parse(...); // how many more overloads?!
Итак, к шаблонам для решения этой неопрятной проблемы, верно?
template <typename type> void parse(type&);
Но я ударился о дорожную кочку…
Попытка решения (код)
#include <iostream>
class Object { public:
// Copy/ Move constructors implicitly defined;
// Same goes for the assignment operator.
constexpr inline Object(void) {}
// Test if the object can be a reference or is an expression value.
template <typename type>
inline static void parse(type) noexcept { std::cout << "[pass-by-value]" << std::endl; }
template <typename type>
inline static void parse(type&) noexcept { std::cout << "[pass-by-reference]" << std::endl; }
};
Передача объекта по значению работает
Object::parse(Object()); // SUCCESS: "pass-by-value"
, но использование ссылки приводит к конфликту функции теста с ее перегрузками.
Object object {};
Object::parse(object); // ERROR: Ambiguous call of `Object::parse` function.
// EXPECTED: "pass-by-reference"
Я предполагаю, что вызов неоднозначен, потому что Перегрузка parse(type)
инициализируется с помощью {type=Object&}
и Перегрузка parse(type&)
инициализируется с помощью {type=Object}
.
Хотя я думал, что перегрузка parse(type&)
предпочтительнее, но, похоже, это не так.
Итак, что мне здесь не хватает?
Вопрос
Как мы можем различить аргумент, который может быть ссылкой, или аргумент, который является константным выражением, использующим функцию шаблона?
Примечание: я пытаюсь предотвратить ненужные копии с пользовательскими объектами, например:
Если я передам Image() [type=Image]
в качестве аргумента, он будет передан по значению. В противном случае он будет передан по ссылке, например:
Image image; // -> image [type=Image&]
Image images[1]; // -> images[0] [type=Image&]
Image *image_p; // -> *(image_p + 0) [type=Image&]