在尝试解决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
也是假的?
答案 0 :(得分:4)
SFINAE仅适用于模板实例化的直接上下文。这是一个较短的例子:
template <class T>
struct X {
template <std::enable_if_t<std::is_pointer<T>::value, int> = 0>
void foo() {
}
};
T
在foo
实例化时已知,因此在替换该函数模板期间不会发生故障。这是一个很难的错误。您甚至无法实例化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>::value
为true
,另一个IsIncrementable<value_type>::value
为false
。由于错误会显示在false
上,这给我的印象是它总是错误的,甚至是!
值。