[英]c++ parameter pack expansion with concepts
如果取消注釋行 #1 和注釋行 #2,為什么會出現編譯錯誤? 演示: https://godbolt.org/z/KW6dhsrKd
#include <utility>
template <typename, std::size_t> concept prefix = true;
template<std::size_t>
struct dummy { template<typename T> constexpr dummy(T){}; };
template <auto N>
consteval auto nth_element(auto... args)
{
return [&]<std::size_t... Is>(std::index_sequence<Is...>) {
//return [](prefix<Is> auto..., auto arg, auto...) { //compile error // #1
return [](dummy<Is> ..., auto arg, auto...) { // OK // #2
return arg;
}(args...);
}(std::make_index_sequence<N>());
}
int main()
{
static_assert(nth_element<0>(1, 2, 3) == 1);
static_assert(nth_element<1>(1, 2, 3) == 2);
static_assert(nth_element<2>(1, 2, 3) == 3);
return 0;
}
來自[dcl.fct]/22 :
一個縮寫的 function 模板等效於一個 function 模板 ([temp.fct]),其模板參數列表包含一個發明類型模板參數,用於 function 聲明的每個通用參數類型占位符,按出現順序排列。 [..] 如果相應的參數聲明聲明了 function 參數包,則發明的類型模板參數是模板參數包。
請注意, prefix<Is> auto...
同時是包和包擴展。
所以轉換后的模板看起來像
[] <prefix<Is>... Args> (Args auto..., auto arg, auto...) {
return arg;
}(args...)
這相當於
[] <typename... Args> requires(prefix<Args, Is> && ...) (Args..., auto arg, auto...) {
return arg;
}(args...)
(這仍然會生成相同的錯誤消息。)
我們可以看到 1) Args處於非推導上下文中並且將始終保持為空,並且 2) Is
和Args
必須在長度上一致才能滿足約束條件。
評論中給出的解決方案不是理想的 IMO,因為創建元組可能相對昂貴(尤其是在編譯時)。 我認為你的解決方案+適當的轉發是目前最好的(直到我們得到適當的包下標)。 即是這樣的:
template<std::size_t>
struct dummy { constexpr dummy(auto&&){}; };
template <std::size_t N, typename... Args>
constexpr decltype(auto) nth_element(Args&&... args) {
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> decltype(auto) {
return [](dummy<Is> ..., auto&& arg, auto&&...) -> decltype(auto) { // OK // #2
return std::forward<decltype(arg)>(arg);
}(std::forward<Args>(args)...);
}(std::make_index_sequence<N>());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.