bool和它的价值怎么都不是假的?

时间:2016-10-12 14:59:11

标签: c++ templates

在尝试解决this (un)problem时,我注意到一种非常奇怪的行为,简而言之,bool为假,!(非值)也是假的。我想知道这是怎么可能的。导致此问题的代码如下:

template<typename T, typename TID = unsigned int>
struct AId {
  typedef AId<T, TID> type;
  typedef T handled_type;
  typedef TID value_type;

private:
  value_type id;

  template<typename _T> struct IsIncrementable
  {
    template<typename _U> using rm_ref = typename std::remove_reference<_U>::type;
    typedef char (&yes)[1];
    typedef char (&no)[2];
    template<class _U>
    static yes test(_U *data, typename std::enable_if<
                      std::is_same<_U, rm_ref<decltype(++(*data))>>::value
                    >::type * = 0);
    static no test(...);
    static const bool value = sizeof(yes) == sizeof(test((rm_ref<_T> *)0));
  };

public:
  explicit AId(const value_type &id) : id(id) {}

...

  //IsIncrementable<value_type>::value is false:
  //error: no type named 'type' in 'struct std::enable_if<false, int>'
  template<typename std::enable_if<IsIncrementable<value_type>::value, int>::type = 0>
  type operator++(int /*postfix*/) { type old(id); ++id; return old; }

  //!IsIncrementable<value_type>::value is also false:
  //error: no type named 'type' in 'struct std::enable_if<false, int>'
  template<typename std::enable_if<!IsIncrementable<value_type>::value, int>::type = 0>
  type operator++(int /*postfix*/) { type old(id); ++id; return old; }
};

IsIncrementable<value_type>::value怎么可能是假的,!IsIncrementable<value_type>::value也是假的?

2 个答案:

答案 0 :(得分:4)

SFINAE仅适用于模板实例化的直接上下文。这是一个较短的例子:

template <class T>
struct X {
    template <std::enable_if_t<std::is_pointer<T>::value, int> = 0>
    void foo() {
    }
};

Tfoo实例化时已知,因此在替换该函数模板期间不会发生故障。这是一个很难的错误。您甚至无法实例化X<int>因为enable_if_t<false, int>已经格式不正确,无论您是否致电foo

您必须引入一个默认类型参数,该参数实际上属于直接上下文:

template <class T>
struct X {
    template <class U=T, std::enable_if_t<std::is_pointer<U>::value, int> = 0>
    void foo() {
    }
};

现在,U上的SFINAE很好 - U是此函数的本地模板参数,因此实例化将被延迟,直到使用此函数。所以X<int>{}很好,X<int>{}.foo()会失败,因为重载解析无法找到可行的重载 - 这个foo()刚被删除。

答案 1 :(得分:0)

这可能对其他成员不公平,因为问题并不在于模板的代码,而在于实例化。

@ Barry's answear解释了为什么SFINAE不会在这里工作,而是提供硬错误。但是如果我用以下函数替换函数:

  static_assert(IsIncrementable<value_type>::value, "It cannot be incrementable");
  static_assert(!IsIncrementable<value_type>::value, "It has to be incrementable");

我仍然在两个断言中都出错。问题是我用两个不同的类实例化模板。对于一个案例,IsIncrementable<value_type>::valuetrue,另一个IsIncrementable<value_type>::valuefalse。由于错误会显示在false上,这给我的印象是它总是错误的,甚至是!值。