簡體   English   中英

部分特化和對 std::void_t<> 的需求

[英]Partial specialization and the need for std::void_t<>

語言律師之一......

我在玩 SFINAE 和 TMP,試圖獲得更深入的理解。

考慮下面的代碼,一個 std::is_default_constructible 的簡單實現

#include <type_traits>

template <typename T, typename = void> struct is_default_constructable : std::false_type {};
template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};

class NC { NC(int); };  // Not default constructable

#include <iostream>
int main(int, char **)
{
    std::cout << "int is_default_constructible? " << is_default_constructable<int>() << std::endl;
    std::cout << "NC is_default_constructible? " << is_default_constructable<NC>() << std::endl;
}

這編譯得很好,但實際上不起作用,它對所有類型都返回 false。

對於 NC 情況,正如我所期望的那樣, T()格式不正確,因此由於 SFINAE 丟棄了專業化並使用了主要模板 (false_type)。 但是對於int情況,我希望將專業化用作decltype(T())是有效的並且等效於T

如果根據<type_traits>的實際代碼,我將專業化更改為

template <typename T> using wrap = void;
template <typename T> struct is_default_constructable<T, wrap<decltype(T())> > : std::true_type {};

std::void_t<>第二個模板參數包裝在std::void_t<>的模型中,這迫使第二個類型為void ),這按預期工作。

更奇怪的是,使用void以外的類型作為主模板或wrap<>的默認類型的這種方案的變體也會失敗,除非這兩種類型相同。

有人可以解釋為什么wrap<>的類型和第二個模板參數默認類型需要相同才能選擇專業化嗎?

(我在 g++ 6.3 版中使用“g++ -Wall --std=c++17”,但我認為這與編譯器無關。)

這不是 SFINAE 或部分專業化排序的結果,而是由於使用了默認模板參數。 非正式地,原因是默認模板參數的應用發生搜索模板定義之前,包括可能的特化。

所以在上面的例子中,說is_default_constructable<int>的代碼實際上是在應用默認的第二個參數后請求實例化模板is_default_constructable<int, void> 然后考慮可能的定義。

“主要”模板定義明確匹配並包含在內。 給定的部分專業化

template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};

實際上是定義is_default_constructable<int, int> ,它與請求的is_default_constructable<int, void>不匹配is_default_constructable<int, void>因此即使替換成功,也會忽略特化。 這將主要定義(繼承 false_type)作為唯一可行的定義,因此它被選中。

當專業化具有wrap<> (或std::void_t<> )以強制第二個 arg 為void ,專業化定義is_default_constructable<int, void>與請求匹配。 這個定義(假設替換成功,即T()格式良好)比主要定義更專業(根據超復雜的專業化排序規則),所以選擇它。

順便說一句,當 T 是引用類型或其他極端情況時,上述幼稚的實現可能無法按預期工作,這是使用所有這些標准庫版本的一個很好的理由。 他們標准委員會的人比我聰明得多,並且已經想到了所有這些事情。

這個答案這個對有些相關問題的答案有更詳細的信息讓我正確。

而且,是的,我無法拼寫可構造的,假設它甚至是一個單詞。 這是使用標准庫的另一個很好的理由。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM