我可以使用std::experimental::is_detected来检查chips1_t是否可以用float*实例化(不能),如下面的static_assert所示:

#include <experimental/type_traits>
#include <type_traits>

template <typename, typename = void>
  struct chips1;

template <typename T>
struct chips1<T*,std::enable_if_t<std::is_same<T,int>::value>> {
  using type = int;
};

template <typename T> using chips1_t = typename chips1<T>::type;

static_assert(!std::experimental::is_detected<chips1_t,float*>::value,"");

如果再尝试使用chips2_t进行检查,则如下所示的类似static_assert将产生编译错误;关于缺少的type成员。谁能告诉我为什么?
struct Base {};

template <typename>
  struct chips2;

template <typename T>
struct chips2<T*> : std::enable_if_t<std::is_same<T,int>::value,Base> {
  using type = int;
};

template <typename T> using chips2_t = typename chips2<T>::type;

static_assert(!std::experimental::is_detected<chips2_t,float*>::value,"");

最佳答案

在第二种情况下,基类不是模板类型的一部分,因此在SFINAE期间不考虑它(这是一个从属基类)
实例化

template <typename T>
struct chips2<T*>
成功,然后编译失败,因为它是从std::enable_if_t<std::is_same<T,int>::value,Base>派生而来的,该:变成了格式错误的表达式。

您不能通过模板的基类来专门化模板。
例如,您不能有两个像这样的竞争专业:
template <typename T>
struct chips2<T*> : std::enable_if_t<std::is_same<T,int>::value,Base> {
  using type = int;
};

template <typename T>
struct chips2<T*> : std::enable_if_t<!std::is_same<T,int>::value,Base> {
  using type = float;
};
从特化的 Angular 来看,它们被认为是相同的(即,从命名的 Angular 来看,它们是相同的,因此编译器将第二个视为对第一个的重新声明)。唯一重要的部分是冒号enable_if之前的所有内容
在第一种情况下,您的chips2直接是模板特化的一部分,因此SFINAE可以正常工作。

另一个注意
在第二篇文章中,您实际上无法用int*以外的任何其他实例化c,请参见以下示例:
struct Base {};

template <typename>
struct chips2
{};

template <typename T>
struct chips2<T*>
   : std::enable_if_t<std::is_same<T,int>::value, Base>
{};

int main(){
    chips2<float*> c;
}
您可能倾向于认为SFINAE将为chips2<T*>选择基类模板,但实际上,由于我上面所说的,它选择了特化chips2<T*>,并且编译失败。

*相关标准为[temp.spec]

其中,simple-template-id的形式为:
模板名称
例如ojit_code。请注意,没有选择还包括其派生的类

09-18 08:34