通过继承检测成语和SFINAE

时间:2017-11-15 17:51:39

标签: c++ templates sfinae

我可以使用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,"");

1 个答案:

答案 0 :(得分:2)

在第二种情况下,基类不是模板类型的一部分,因此在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;
};

从专业化的角度来看,它们被认为是相同的(即,从命名的角度看它们是相同的,因此编译器会认为第二个是第一个的重新声明)。唯一重要的部分是结肠:

之前的一切

在第一种情况下,您的enable_if直接属于模板专精化,因此SFINAE正常运作。

另一个注意事项

在第二个问题中,您实际上无法使用chips2以外的任何内容实例化int*,请参阅以下示例:

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将为c选择基类模板,但实际上它选择了专门化chips2<T*>,因为我上面所说的,编译失败。

* [temp.spec]

的相关标准
  

显式专用的类的名称应为 simple-template-id。

simple-template-id 的形式如下:
template-name&lt; template-argument-listopt&gt;

e.g。 chips2<T*>。请注意,没有选项也包括它从

派生的类