久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

void_t“可以實現概念"?

void_t quot;can implement conceptsquot;?(void_t“可以實現概念?)
本文介紹了void_t“可以實現概念"?的處理方法,對大家解決問題具有一定的參考價值,需要的朋友們下面隨著小編來一起學習吧!

問題描述

限時送ChatGPT賬號..

我正在觀看 Walter Brown 的 CppCon2014 的第二部分談論模板元編程,在此期間,他討論了他新穎的void_t<> 構造的使用.在他的演講中,Peter Sommerlad 問了他一個我不太明白的問題.(鏈接直接指向問題,討論中的代碼直接發生在此之前)

I was watching the second part of Walter Brown's CppCon2014 talk on template metaprogramming, during which he discussed the uses of his novel void_t<> construction. During his presentation Peter Sommerlad asked him a question that I didn't quite understand. (link goes directly to the question, the code under discussion took place directly before that)

薩默拉德問道

Walter,這是否意味著我們現在實際上可以實現精簡版的概念?

Walter, would that mean we actually can implement concepts lite right now?

沃爾特回應了

哦耶!我已經完成了……它的語法不太一樣.

Oh yeah! I've done it ... It doesn't have quite the same syntax.

我理解這次交流是關于 Concepts Lite.這種模式真的那個通用嗎?無論出于何種原因,我都沒有看到它.有人可以解釋(或草圖)這樣的東西會是什么樣子嗎?這只是關于 enable_if 和定義特征,還是提問者指的是什么?

I understood this exchange to be about Concepts Lite. Is this pattern really that versatile? For whatever reason, I am not seeing it. Can someone explain (or sketch) how something like this might look? Is this just about enable_if and defining traits, or what was the questioner referring to?

void_t 模板定義如下:

template<class ...> using void_t = void;

他使用 then 來檢測類型語句是否格式正確,并使用它來實現 is_copy_assignable 類型特征:

He uses this then to detect if type statements are well formed, using this to implement the is_copy_assignable type trait:

//helper type
template<class T>
using copy_assignment_t
= decltype(declval<T&>() = declval<T const&>());

//base case template
template<class T, class=void>
struct is_copy_assignable : std::false_type {};

//SFINAE version only for types where copy_assignment_t<T> is well-formed.
template<class T>
struct is_copy_assignable<T, void_t<copy_assignment_t<T>>> 
: std::is_same<copy_assignment_t<T>,T&> {};

因為談話,我明白這個例子是如何工作的,但我不明白我們如何從這里得到像 Concepts Lite 這樣的東西.

Because of the talk, I understand how this example works, but I don't see how we get from here to something like Concepts Lite.

推薦答案

是的,concepts lite 基本上裝扮了 SFINAE.此外,它還允許進行更深入的內省,以實現更好的重載.然而,這僅在概念謂詞被定義為 concept bool 時才有效.改進的重載不適用于當前的概念謂詞,但可以使用條件重載.讓我們看看如何在 C++14 中定義謂詞、約束模板和重載函數.這有點長,但它介紹了如何在 C++14 中創建完成此任務所需的所有工具.

Yes, concepts lite basically dresses up SFINAE. Plus it allows deeper introspection to allow for better overloading. However that only works if the concept predicates are defined as concept bool. The improved overloading does not work with the current concept predicates, but conditional overloading can be used. Lets look how we can define predicates, constrain templates, and overload functions in C++14. This is kind of long, but it goes over how to create all of the tools needed to accomplish this in C++14.

首先,閱讀帶有所有 std::declvaldecltype 的謂詞有點難看.相反,我們可以利用這樣一個事實,即我們可以使用尾隨 decltype 來約束函數(來自 Eric Niebler 的博客文章 這里),像這樣:

First, it is kind of ugly to read the predicate with all the std::declval and decltype everywhere. Instead, we can take advantage of the fact that we can constrain a function using a trailing decltype(from Eric Niebler’s blog post here), like this:

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(++x);
};

因此,如果 ++x 無效,則 requires_ 成員函數不可調用.所以我們可以創建一個 models trait 來檢查 requires_ 是否可以使用 void_t 調用:

So if ++x is not valid, then the requires_ member function is not callable. So we can create a models trait that just checks if requires_ is callable using void_t:

template<class Concept, class Enable=void>
struct models
: std::false_type
{};

template<class Concept, class... Ts>
struct models<Concept(Ts...), void_t< 
    decltype(std::declval<Concept>().requires_(std::declval<Ts>()...))
>>
: std::true_type
{};

約束模板

所以當我們想基于概念約束模板時,我們仍然需要使用enable_if,但我們可以使用這個宏來幫助使其更清晰:

Constraining Templates

So when we want to constrain the template based on the concept, we will still need to use enable_if, but we can use this macro to help make it cleaner:

#define REQUIRES(...) typename std::enable_if<(__VA_ARGS__), int>::type = 0

所以我們可以定義一個基于Incrementable概念約束的increment函數:

So we can define an increment function that is constrained based on Incrementable concept:

template<class T, REQUIRES(models<Incrementable(T)>())>
void increment(T& x)
{
    ++x;
}

所以如果我們用不是Incrementable的東西調用increment,我們會得到這樣的錯誤:

So if we call increment with something that is not Incrementable, we will get an error like this:

test.cpp:23:5: error: no matching function for call to 'incrementable'
    incrementable(f);
    ^~~~~~~~~~~~~
test.cpp:11:19: note: candidate template ignored: disabled by 'enable_if' [with T = foo]
template<class T, REQUIRES(models<Incrementable(T)>())>
                  ^

重載函數

現在如果我們要做重載,我們要使用條件重載.假設我們要創建一個 std::advance使用概念謂詞,我們可以這樣定義它(現在我們將忽略可遞減的情況):

Overloading Functions

Now if we want to do overloading, we want to use conditional overloading. Say we want to create an std::advance using concept predicates, we could define it like this(for now we will ignore the decrementable case):

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(++x);
};

struct Advanceable
{
    template<class T, class I>
    auto requires_(T&& x, I&& i) -> decltype(x += i);
};

template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
void advance(Iterator& it, int n)
{
    it += n;
}

template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
void advance(Iterator& it, int n)
{
    while (n--) ++it;
}

然而,當它與 std::vector 迭代器.我們想要做的是對調用進行排序,我們可以使用條件重載來完成.可以考慮寫這樣的東西(這不是有效的 C++):

However, this causes an ambiguous overload(In concepts lite this would still be an ambiguous overload unless we change our predicates to refer to the other predicates in a concept bool) when its used with std::vector iterator. What we want to do is order the calls, which we can do using conditional overloading. It can be thought of writing something like this(which is not valid C++):

template<class Iterator>
void advance(Iterator& it, int n) if (models<Advanceable(Iterator, int)>())
{
    it += n;
} 
else if (models<Incrementable(Iterator)>())
{
    while (n--) ++it;
}

所以如果第一個函數沒有被調用,它將調用下一個函數.因此,讓我們從為兩個功能實現它開始.我們將創建一個名為 basic_conditional 的類,它接受兩個函數對象作為模板參數:

So if the first function isn't called, it will call the next function. So lets start by implementing it for two functions. We will create a class called basic_conditional which accepts two function objects as template parameters:

struct Callable
{
    template<class F, class... Ts>
    auto requires_(F&& f, Ts&&... xs) -> decltype(
        f(std::forward<Ts>(xs)...)
    );
};

template<class F1, class F2>
struct basic_conditional
{
    // We don't need to use a requires clause here because the trailing
    // `decltype` will constrain the template for us.
    template<class... Ts>
    auto operator()(Ts&&... xs) -> decltype(F1()(std::forward<Ts>(xs)...))
    {
        return F1()(std::forward<Ts>(xs)...);
    }
    // Here we add a requires clause to make this function callable only if
    // `F1` is not callable.
    template<class... Ts, REQUIRES(!models<Callable(F1, Ts&&...)>())>
    auto operator()(Ts&&... xs) -> decltype(F2()(std::forward<Ts>(xs)...))
    {
        return F2()(std::forward<Ts>(xs)...);
    }
};

所以現在這意味著我們需要將我們的函數定義為函數對象:

So now that means we need to define our functions as functions objects instead:

struct advance_advanceable
{
    template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
    void operator()(Iterator& it, int n) const
    {
        it += n;
    }
};

struct advance_incrementable
{
    template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        while (n--) ++it;
    }
};

static conditional<advance_advanceable, advance_incrementable> advance = {};

所以現在如果我們嘗試將它與 std::vector 一起使用:

So now if we try to use it with an std::vector:

std::vector<int> v = { 1, 2, 3, 4, 5, 6 };
auto iterator = v.begin();
advance(iterator, 4);
std::cout << *iterator << std::endl;

它會編譯并打印出5.

然而,std::advance 實際上有三個重載,所以我們可以使用 basic_conditional 來實現適用于任意數量的 conditional使用遞歸的函數:

However, std::advance actually has three overloads, so we can use the basic_conditional to implement conditional that works for any number of functions using recursion:

template<class F, class... Fs>
struct conditional : basic_conditional<F, conditional<Fs...>>
{};

template<class F>
struct conditional<F> : F
{};

所以,現在我們可以像這樣編寫完整的std::advance:

So, now we can write the full std::advance like this:

struct Incrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(++x);
};

struct Decrementable
{
    template<class T>
    auto requires_(T&& x) -> decltype(--x);
};

struct Advanceable
{
    template<class T, class I>
    auto requires_(T&& x, I&& i) -> decltype(x += i);
};

struct advance_advanceable
{
    template<class Iterator, REQUIRES(models<Advanceable(Iterator, int)>())>
    void operator()(Iterator& it, int n) const
    {
        it += n;
    }
};

struct advance_decrementable
{
    template<class Iterator, REQUIRES(models<Decrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        if (n > 0) while (n--) ++it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    }
};

struct advance_incrementable
{
    template<class Iterator, REQUIRES(models<Incrementable(Iterator)>())>
    void operator()(Iterator& it, int n) const
    {
        while (n--) ++it;
    }
};

static conditional<advance_advanceable, advance_decrementable, advance_incrementable> advance = {};

Lambda 重載

然而,此外,我們可以使用 lambdas 代替函數對象來編寫它,這有助于使其編寫起來更清晰.所以我們使用這個 STATIC_LAMBDA 宏來在編譯時構造 lambdas:

Overloading With Lambdas

However, additionally, we could use lambdas to write it instead of function objects which can help make it cleaner to write. So we use this STATIC_LAMBDA macro to construct lambdas at compile time:

struct wrapper_factor
{
    template<class F>
    constexpr wrapper<F> operator += (F*)
    {
        return {};
    }
};

struct addr_add
{
    template<class T>
    friend typename std::remove_reference<T>::type *operator+(addr_add, T &&t) 
    {
        return &t;
    }
};

#define STATIC_LAMBDA wrapper_factor() += true ? nullptr : addr_add() + []

并添加一個make_conditional函數,即constexpr:

template<class... Fs>
constexpr conditional<Fs...> make_conditional(Fs...)
{
    return {};
}

那么我們現在可以像這樣編寫advance函數:

Then we can now write the advance function like this:

constexpr const advance = make_conditional(
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Advanceable(decltype(it), int)>()))
    {
        it += n;
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Decrementable(decltype(it))>()))
    {
        if (n > 0) while (n--) ++it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(models<Incrementable(decltype(it))>()))
    {
        while (n--) ++it;
    }
);

這比使用函數對象版本更緊湊和可讀.

Which is little more compact and readable than using the function object versions.

另外,我們可以定義一個modeled函數來減少decltype的丑陋:

Additionally, we could define a modeled function to reduce down the decltype ugliness:

template<class Concept, class... Ts>
constexpr auto modeled(Ts&&...)
{
    return models<Concept(Ts...)>();
}

constexpr const advance = make_conditional(
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Advanceable>(it, n)))
    {
        it += n;
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Decrementable>(it)))
    {
        if (n > 0) while (n--) ++it;
        else 
        {
            n *= -1;
            while (n--) --it;
        }
    },
    STATIC_LAMBDA(auto& it, int n, REQUIRES(modeled<Incrementable>(it)))
    {
        while (n--) ++it;
    }
);

最后,如果您有興趣使用現有的庫解決方案(而不是像我展示的那樣滾動自己的解決方案).Tick 庫提供了一個定義概念和約束模板的框架.而 Fit 庫可以處理函數和重載.

Finally, if you are interested in using existing library solutions(rather than rolling your own like I've shown). There is the Tick library that provides a framework for defining concepts and constraining templates. And the Fit library can handle the functions and overloading.

這篇關于void_t“可以實現概念"?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!

【網站聲明】本站部分內容來源于互聯網,旨在幫助大家更快的解決問題,如果有圖片或者內容侵犯了您的權益,請聯系我們刪除處理,感謝您的支持!

相關文檔推薦

Difference between std::reference_wrapper and simple pointer?(std::reference_wrapper 和簡單指針的區別?)
Difference between const. pointer and reference?(常量之間的區別.指針和引用?)
How to access the contents of a vector from a pointer to the vector in C++?(c++ - 如何從指向向量的指針訪問向量的內容?)
Meaning of *amp; and **amp; in C++(*amp; 的含義和**amp;在 C++ 中)
Why can#39;t I do polymorphism with normal variables?(為什么我不能對普通變量進行多態?)
Dereferencing deleted pointers always result in an Access Violation?(取消引用已刪除的指針總是會導致訪問沖突?)
主站蜘蛛池模板: 久久久久久精 | 亚洲综合第一页 | 男女爱爱网站 | 激情五月综合 | 欧美日韩国产一区二区三区不卡 | 一区二区三区韩国 | 中文字幕二区 | 国产99久久久国产精品 | 女女百合av大片一区二区三区九县 | 国产三区av | www.天天操 | 亚洲一区二区三区高清 | 欧美一级三级在线观看 | 久久久久久久久久久久久久国产 | 天天操天天干天天曰 | 亚洲美乳中文字幕 | 夜夜爽99久久国产综合精品女不卡 | 在线观看日本高清二区 | 国产三级 | 亚洲欧美在线免费观看 | 一区二区三区免费网站 | 日韩精品中文字幕一区二区三区 | 另类在线| 国产黄色大片在线免费观看 | 亚洲精品一二三区 | 欧美一区二区在线视频 | 在线观看视频中文字幕 | 天天操天天干天天透 | 一区影视| 四虎影音 | 日韩美香港a一级毛片免费 国产综合av | 国产农村妇女毛片精品久久麻豆 | 一级黄色片毛片 | 国产精品久久久久久久岛一牛影视 | 人人射人人插 | 蜜月aⅴ免费一区二区三区 99re在线视频 | 国产精品久久久久久久久 | 欧产日产国产精品视频 | 99精品电影| 第四色播日韩第一页 | 久久国产精品无码网站 |