[英]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.