Препращане на препратка с аргумент по подразбиране?

Имам проблеми с опитите си да разбера как да посоча аргументи по подразбиране за препращаща препратка (по-рано наричана Универсални препратки от Скот Майерс).

Ето пример за код, който се опитва да направи това, което искам да направя:

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" );

}

Също така се предлага в Coliru.

Преглеждайки грешките, откривате, че можете да го накарате да работи, като зададете по подразбиране аргумента на шаблона и след това конструирате аргумента по подразбиране след това:

// 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() ) {

}

Също в Coliru.

Това ли е "правилният" начин за справяне с това? Какъв трябва да бъде синтаксисът, който използвам? Има ли няколко начина за постигане на желания ефект от „препратени препратки по подразбиране“? По какъв начин трябва да пиша това? Също така имайте предвид, че по-късно ще поръся тонове SFINAE върху кода, така че бих предпочел много повече нещо, което не включва писане на множество претоварвания.


person Community    schedule 27.11.2014    source източник


Отговори (1)


Първо, типовете шаблони не могат да бъдат изведени от аргументи по подразбиране. Така че можем само да търсим други начини за постигане на идеята да можем по избор да посочим аргумент, който да съответства на препращаща препратка.

Това решение се предполага:

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, може би тази публикация ще има някои идеи: Как да разрешите конструкция по подразбиране при използване на универсална препратка в конструктор

person M.M    schedule 27.11.2014