У меня возникли проблемы при попытке выяснить, как задать аргументы по умолчанию для ссылки пересылки (ранее назывался Универсальные ссылки Скотт Мейерс).
Вот пример кода, пытающегося сделать то, что я хочу сделать:
struct encoder_t {
} const encoder = {};
struct validator_t {
} const validator = {};
struct test {
template <typename Range, typename Encoding, typename Validation>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator ) {
}
};
int main() {
test( "woof" );
}
Перебирая ошибки, вы обнаруживаете, что можете заставить его работать, установив аргумент шаблона по умолчанию, а затем построив аргумент по умолчанию:
// Works! But the syntax is strange... potential ramifications/deduction mishaps?
// Is this the "proper" way to default these arguments?
template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = Encoding(), Validation&& validation = Validation() ) {
}
Это «правильный» способ справиться с этим? Какой должен быть синтаксис, который я использую? Есть ли несколько способов получить желаемый эффект «переадресованных ссылок по умолчанию»? Каким образом я должен писать это? Также имейте в виду, что позже я буду разбрасывать тонны SFINAE на код, поэтому я бы предпочел что-то, что не включает в себя написание нескольких перегрузок.
Прежде всего, типы шаблонов не могут быть выведены из аргументов по умолчанию. Таким образом, мы можем только искать другие способы достижения идеи возможности опционально указать аргумент, соответствующий ссылке для пересылки.
Этот обходной путь предлагает себя:
template <typename Range, typename Encoding = encoder_t, typename Validation = validator_t>
test ( Range&& range, Encoding&& encoding = encoder, Validation&& validation = validator )
{
}
однако это терпит неудачу: Пересылка ссылок работает, выводя тип шаблона как ссылочный тип, но вы указали тип объекта; и ссылка rvalue теперь не может привязываться к lvalues ваших фиктивных объектов.
Как вы говорите в своем посте, вы можете исправить это, сделав значения по умолчанию временным объектом. encoder_t{}
вместо фиктивного объекта. Этот вопрос подтверждает, что ссылка остается Пересылочной ссылкой в этом случае.
Другим обходным решением будет использование отдельных конструкторов вместо аргументов по умолчанию:
template <typename Range>
test ( Range&& range )
{
}
template <typename Range, typename Encoding>
test ( Range&& range, Encoding&& encoding )
{
}
template <typename Range, typename Encoding, typename Validation>
test ( Range&& range, Encoding&& encoding, Validation&& validation )
{
}
В зависимости от того, что именно вы делаете в теле конструктора, вы можете реализовать это с помощью делегирования конструктора.
Поскольку вы упомянули о намерении добавить SFINAE, возможно, у этого поста будут некоторые идеи: Как разрешить конструкцию по умолчанию при использовании универсальной ссылки в конструкторе