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

void_t“可以實(shí)現(xiàn)概念"?

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

問題描述

限時(shí)送ChatGPT賬號..

我正在觀看 Walter Brown 的 CppCon2014 的第二部分談?wù)撃0逶幊?,在此期間,他討論了他新穎的void_t<> 構(gòu)造的使用.在他的演講中,Peter Sommerlad 問了他一個(gè)我不太明白的問題.(鏈接直接指向問題,討論中的代碼直接發(fā)生在此之前)

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,這是否意味著我們現(xiàn)在實(shí)際上可以實(shí)現(xiàn)精簡版的概念?

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

沃爾特回應(yīng)了

哦耶!我已經(jīng)完成了……它的語法不太一樣.

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

我理解這次交流是關(guān)于 Concepts Lite.這種模式真的那個(gè)通用嗎?無論出于何種原因,我都沒有看到它.有人可以解釋(或草圖)這樣的東西會是什么樣子嗎?這只是關(guān)于 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 來檢測類型語句是否格式正確,并使用它來實(shí)現(xiàn) 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&> {};

因?yàn)檎勗挘颐靼走@個(gè)例子是如何工作的,但我不明白我們?nèi)绾螐倪@里得到像 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.此外,它還允許進(jìn)行更深入的內(nèi)省,以實(shí)現(xiàn)更好的重載.然而,這僅在概念謂詞被定義為 concept bool 時(shí)才有效.改進(jìn)的重載不適用于當(dāng)前的概念謂詞,但可以使用條件重載.讓我們看看如何在 C++14 中定義謂詞、約束模板和重載函數(shù).這有點(diǎn)長,但它介紹了如何在 C++14 中創(chuàng)建完成此任務(wù)所需的所有工具.

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 的謂詞有點(diǎn)難看.相反,我們可以利用這樣一個(gè)事實(shí),即我們可以使用尾隨 decltype 來約束函數(shù)(來自 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_ 成員函數(shù)不可調(diào)用.所以我們可以創(chuàng)建一個(gè) models trait 來檢查 requires_ 是否可以使用 void_t 調(diào)用:

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
{};

約束模板

所以當(dāng)我們想基于概念約束模板時(shí),我們?nèi)匀恍枰褂?code>enable_if,但我們可以使用這個(gè)宏來幫助使其更清晰:

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

所以我們可以定義一個(gè)基于Incrementable概念約束的increment函數(shù):

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的東西調(diào)用increment,我們會得到這樣的錯(cuò)誤:

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)>())>
                  ^

重載函數(shù)

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

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;
}

然而,當(dāng)它與 std::vector 迭代器.我們想要做的是對調(diào)用進(jìn)行排序,我們可以使用條件重載來完成.可以考慮寫這樣的東西(這不是有效的 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;
}

所以如果第一個(gè)函數(shù)沒有被調(diào)用,它將調(diào)用下一個(gè)函數(shù).因此,讓我們從為兩個(gè)功能實(shí)現(xiàn)它開始.我們將創(chuàng)建一個(gè)名為 basic_conditional 的類,它接受兩個(gè)函數(shù)對象作為模板參數(shù):

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)...);
    }
};

所以現(xiàn)在這意味著我們需要將我們的函數(shù)定義為函數(shù)對象:

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 = {};

所以現(xiàn)在如果我們嘗試將它與 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 實(shí)際上有三個(gè)重載,所以我們可以使用 basic_conditional 來實(shí)現(xiàn)適用于任意數(shù)量的 conditional使用遞歸的函數(shù):

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
{};

所以,現(xiàn)在我們可以像這樣編寫完整的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 代替函數(shù)對象來編寫它,這有助于使其編寫起來更清晰.所以我們使用這個(gè) STATIC_LAMBDA 宏來在編譯時(shí)構(gòu)造 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() + []

并添加一個(gè)make_conditional函數(shù),即constexpr:

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

那么我們現(xiàn)在可以像這樣編寫advance函數(shù):

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

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

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

另外,我們可以定義一個(gè)modeled函數(shù)來減少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;
    }
);

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

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.

這篇關(guān)于void_t“可以實(shí)現(xiàn)概念"?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!

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

相關(guān)文檔推薦

Difference between std::reference_wrapper and simple pointer?(std::reference_wrapper 和簡單指針的區(qū)別?)
Difference between const. pointer and reference?(常量之間的區(qū)別.指針和引用?)
How to access the contents of a vector from a pointer to the vector in C++?(c++ - 如何從指向向量的指針訪問向量的內(nèi)容?)
Meaning of *amp; and **amp; in C++(*amp; 的含義和**amp;在 C++ 中)
Why can#39;t I do polymorphism with normal variables?(為什么我不能對普通變量進(jìn)行多態(tài)?)
Dereferencing deleted pointers always result in an Access Violation?(取消引用已刪除的指針總是會導(dǎo)致訪問沖突?)
主站蜘蛛池模板: 日韩中字幕 | 欧美日韩一本 | 91视频大全 | 婷婷色国产偷v国产偷v小说 | 久久久久久一区 | 先锋影音资源网站 | 日韩免费av网站 | 国产精品久久久久久久一区探花 | 在线观看视频一区 | 亚洲在线成人 | 国产视频一区二区 | 国产精品揄拍一区二区 | 国产精品a久久久久 | 欧美一区二区三区久久精品 | japan21xxxxhd美女 日本欧美国产在线 | 精品视频在线免费观看 | 国产一区二区久久久 | 日韩av在线一区 | 精品久久久久一区二区国产 | 日韩高清一区二区 | 男人天堂免费在线 | 亚洲精品视频在线 | 91精品国产综合久久婷婷香蕉 | 久久久久久亚洲欧洲 | 欧美日韩在线观看一区二区三区 | 久久综合国产精品 | 中文精品一区二区 | 有码在线 | 精品一区二区三区在线观看国产 | 天天天插 | 中文字幕在线视频精品 | 天天看片天天干 | 欧美精品在线一区 | 久久久日韩精品一区二区三区 | 91色在线视频 | 午夜视频在线观看网址 | 在线观看毛片网站 | 亚洲综合激情 | 99久久久久久 | 久久国内精品 | 国产极品91 |