2017-04-25 106 views
8

考慮following code匹配的別名模板作爲模板參數

#include <type_traits> 

template<template<class...> class T, class... U> 
struct is_specialization_of : std::false_type{}; 

template<template<class...> class T, class... U> 
struct is_specialization_of<T, T<U...>> : std::true_type{}; 

template<class T, class U = int> 
struct test{}; 

// (1) ok 
static_assert(is_specialization_of<test, test<int>>::value, "1"); 

template<class T> 
using alias = test<T>; 

// (2) fails 
static_assert(is_specialization_of<alias, alias<int>>::value, "2"); 

int main() 
{ 
} 

爲什麼(2),即static_assert使用別名模板,失敗?

(2)中的模板參數推導過程如何與(1)中的模板參數推導過程不同?

+3

[CWG 1286](http://open-std.org/JTC1/SC22/WG21/docs/cwg_active。 html#1286) – cpplearner

回答

6

這是CWG issue 1286。問題是:aliastest是否相等?過去有在[temp.type]其例子表明yz具有相同類型的位置:

template<template<class> class TT> struct X { }; 
template<class> struct Y { }; 
template<class T> using Z = Y<T>; 
X<Y> y; 
X<Z> z; 

的示例作爲其一部分CWG defect 1244得到糾正 - 這正確地存在指示[temp.alias]中沒有任何措辭,它實際上指定別名模板等同於它們別名的模板。唯一的措詞有指別名模板特的等價:

模板id專業化的別名模板的,它相當於通過其模板的取代得到的相關類型 - 參數模板參數,type-id的別名模板。

的意圖是很明顯的是yz有相同的類型在這個例子中,這意味着ZY實際上是等價的。但除非通過該決議的措詞,否則它們不是。今天,aliastest不是等效,但是alias<int>test<int>。這意味着is_specialization_of<alias, alias<int>>is_specialization_of<alias, test<int>>,其中aliastest是唯一的,這將不符合您的部分專業化,因此是false_type

而且,即使通過在#措辭的1286,testalias仍然沒有明顯的原因是test有兩個模板參數和別名需要一個模板參數相當於。決議措辭的例子模仿的榜樣,在這裏闡明意圖:

template<typename T, U = T> struct A; 

// ... 

template<typename V> 
    using D = A<V>;  // not equivalent to A: 
         // different number of parameters 
+1

有趣的是,如果我們改變'test'來獲得一個模板參數,那麼(2)仍然不能用任何Clang和GCC <4.9進行編譯。這意味着GCC> = 4.9已經實現了#1286。 –

+1

@IgorR。那麼,1286是不會被採納的。所以這可能是不正確的。 – Barry

2

我認爲沒有模板參數列表的別名模板名稱不等同於關聯類型的名稱。因爲標準規定只有一個這樣的情況:

14.5.7別名模板[temp.alias]

  • 當模板id是指一個別名模板的專業化,它相當於通過用alias 模板的type-id中的模板參數替換其模板參數而獲得的關聯類型 。 [注:一個別名模板名稱是從來沒有deduced.年底注]
  • works fine

    static_assert(is_specialization_of<test, alias<int>>::value, "2"); 
    
    +0

    那麼,爲什麼如果我們刪除'test'的第二個模板參數'U',一切都編譯好? –

    +0

    是否因爲「別名模板名稱從未被推論出」。試圖推斷專業化的參數來選擇部分專業化。當編譯器試圖在專業化中推導出'T'時,它不會將'alias'視爲一種可能性? – TrentP

    +1

    現在實際上是17.5.7,在[this]之後(https://github.com/cplusplus/draft/commit/ec4ca6fc07907ea817152970c45d4c04c86d3c5c);請使用永久名稱,即本例中的[temp.alias]。 (這可以鏈接到:[http://eel.is/c++draft/temp.alias](http://eel.is/c++draft/temp.alias)。) – Griwes