簡體   English   中英

GCC / CLang對模板模板參數的部分特化不一致

[英]GCC/CLang disagree on partial specialization of template template parameter

GCC和clang對此代碼持不同意見。

#include <type_traits>

template <typename T, template <typename...> typename Tpl> 
struct storage {
    using type_t = T;

    template <typename... Args>
    using storage_tpl = Tpl<Args...>;
};

template <typename T, template <typename...> typename>
struct F{
    constexpr static int x = 1;
};

template <typename T >
struct F<T, std::void_t>{
    constexpr static int x = 2;
};

int f() {
    using S = storage<int, std::void_t>;

    static_assert(F<int, S::storage_tpl>().x == 2);

    return F<int, S::storage_tpl>().x;
}

根據clang S::storage_tpl不是std::void_t ; 結果,它選擇主模板F而不是部分特化,從而選擇斷言。

乍一看,看起來GCC是正確的,因為它理解嵌套模板只是std::void_t的別名,但也許它太聰明了,標准要求S::storage_tplstd::void_t必須是兩個不同的模板。

誰是對的?

目前看來這是未指定的,而且對於TC而言,它看起來像CWG缺陷報告1286所述,其中說:

通過更改17.5 [temp.type]第1段中的示例解決了問題1244

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

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

事實上,最初的意圖是該例子應該是正確的; 然而,缺少這樣做的規范性措辭。 17.6.7 [temp.alias]的當前措辭僅涉及別名模板的特化與替換后的type-id的等價性。 需要添加措辭,指定別名模板本身在何種情況下等同於類模板。

並提出以下決議:

在17.6.7 [temp.alias]第2段之后添加以下新段落:

當別名模板聲明中的type-id(稱為A)由一個simple-template-id組成時,其中template-argument-list由一個標識符列表組成,這些標識符將A的每個模板參數命名為恰好一次它們出現在A的template-parameter-list中的順序,如果A和T具有相同數量的模板參數,則別名模板等同於simple-template-id中命名的模板(稱為T)。 [腳注: 此規則具有傳遞性:如果別名模板A等同於另一個等同於模板C的別名模板B,則A也等同於C,A和B也相互等效 - 尾注] [例子:

  template<typename T, U = T> struct A; template<typename V, typename W> using B = A<V, W>; // equivalent to A template<typename V, typename W> using C = A<V>; // not equivalent to A: // not all parameters used template<typename V> using D = A<V>; // not equivalent to A: // different number of parameters template<typename V, typename W> using E = A<W, V>; // not equivalent to A: // template-arguments in wrong order template<typename V, typename W = int> using F = A<V, W>; // equivalent to A: // default arguments not considered template<typename V, typename W> using G = A<V, W>; // equivalent to A and B template<typename V, typename W> using H = E<V, W>; // equivalent to E template<typename V, typename W> using I = A<V, typename W::type>; // not equivalent to A: // argument not identifier 

- 末端的例子]

但是此解決方案存在問題,缺陷報告仍然有效。

暫無
暫無

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

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