Проблема с предложением required внутри if constexpr

При попытке реализовать if constexpr с requires clause на основе if constexpr и требует-выражения для специальной проверки понятий столкнулся со следующей проблемой:

template<class P>
concept TuplePair = requires(P p) {
    requires std::tuple_size<P>::value == 2;
    std::get<0>(p);
    std::get<1>(p);
};

void print(const auto& p) {
    if constexpr( TuplePair<decltype(p)> ) {
        std::cout << std::get<0>(p) << ", " << std::get<1>(p) << std::endl;
    }
    else {
        std::cout << "else" << std::endl;
    }
}

int main() {
    // justifiably prints 'else':
    print(std::make_tuple(3, 4, 5));

    // prints 'else' even though this is a valid TuplePair:
    print(std::make_tuple(1, 2));
}

Что не так с if constexpr requires clause?


person Amir Kirsh    schedule 23.02.2020    source источник
comment
Очевидно, проблема в том, что вы не назвали это понятие Twople.   -  person Casey    schedule 24.02.2020
comment
Спасибо, @Casey, для меня большая честь иметь команду concepts вокруг моих глупых вопросов. Twople должен четко сообщать компилятору о значении вещи и устранять остальную часть кода :-)   -  person Amir Kirsh    schedule 25.02.2020


Ответы (1)


p — это ссылка, а decltype(p) — это ссылочный тип. Для ссылочного типа std::tuple_size работать будет некорректно. Так что проверка концепции не проходит. Вы можете использовать std::remove_cvref_t для получения простого референтного типа

TuplePair<std::remove_cvref_t<decltype(p)>>

Текущая демонстрация

person StoryTeller - Unslander Monica    schedule 23.02.2020
comment
спасибо, элементарно :-) есть ли способ сократить выражение, заставить TuplePair (или дополнительную другую концепцию) вести себя как bool, чтобы выражение могло быть просто: if constexpr( TuplePair‹std::remove_cvref_t‹decltype(p)› › )? - person Amir Kirsh; 23.02.2020
comment
@AmirKirsh - я не уверен, что понимаю. Ваше предложение уже должно работать godbolt.org/z/LPsNbh - person StoryTeller - Unslander Monica; 23.02.2020
comment
@AmirKirsh В качестве альтернативы вы можете использовать две перегрузки: void print(const TuplePair auto& p) и void print(const auto& p) для обработки двух случаев, в зависимости от варианта использования. - person L. F.; 23.02.2020
comment
Почему бы просто не использовать (традиционный) параметр шаблона с const T&, чтобы T не включал ссылку? - person Davis Herring; 23.02.2020
comment
@DavisHerring - Вы бы хотели обратиться к ОП, а не ко мне. - person StoryTeller - Unslander Monica; 23.02.2020
comment
@StoryTeller-UnslanderMonica: Ваш ответ — что нужно вызвать TuplePair для базового нессылочного типа — верен; Я просто предложил другой способ написать это (без std::remove_cvref_t), что казалось разумной корректировкой/дополнением к нему. - person Davis Herring; 23.02.2020
comment
@DavisHerring - я предпочитаю максимально ограничивать себя существующей реализацией OP. Это просто вопрос предпочтения при ответе. Таким образом, предложение альтернативы не приходит на ум. Не сказать, что это неразумно. Вы можете опубликовать другой ответ. Я не думаю, что один ответ обязательно должен содержать все варианты. Разнообразие ответов — сильная сторона SO. Это позволяет системам экспертной оценки сопоставлять различные подходы друг с другом. - person StoryTeller - Unslander Monica; 23.02.2020
comment
@StoryTeller-UnslanderМоника: Конечно, в любом случае есть смысл. Поскольку вопрос был «Что не так…?», а не «Как мне…?», кажется, что «У вас есть ссылка» является (уникальным) ответом, и я не хотел бы повторять (и конкурировать) с ним. просто предложить другой путь вперед. - person Davis Herring; 23.02.2020
comment
@DavisHerring Основная проблема для меня заключалась в изучении синтаксиса понятий. Так что ответ StoryTeller точно соответствует тому, что я искал. Оценивая, конечно, другие предложенные альтернативы, но цель здесь состояла в том, чтобы заставить if constexpr работать с понятиями. - person Amir Kirsh; 23.02.2020
comment
Эта проблема снова поднимает вопрос о том, почему std::tuple_size не был специализирован также для ссылочного типа - person Amir Kirsh; 25.02.2020
comment
@Amir Kirsh 1. Я думаю, что стандарт разрешает вам добавлять такую ​​специализацию. 2. Я согласен с ответом там, это ссылка, а не кортеж, поэтому у него нет размера. Кажется, согласуется с другими вещами в библиотеке. - person Yehezkel B.; 25.02.2020