为什么我不能将继承的错误用作 SFINAE?
Why I can't use inheritance's error as SFINAE?
我有这段代码,但它不能编译:
#include <iostream>
#include <stdexcept>
#include <cassert>
template< class > struct id{};
template< class U, class V> struct base: public id<U>, public id<V>
{
static const bool value = true;
};
template< class U, class V>
struct is_different
{
typedef char (&true_)[1];
typedef char (&false_)[2];
template< class T, class K, bool = base<T,K>::value >
struct checker;
template< class T, class K>
static true_ test( checker<T,K>* );
template< class , class >
static false_ test(...);
static const bool value = sizeof( test<U,V>(0) ) == sizeof(true_);
};
int main (void)
{
bool b1 = is_different<int,float>::value;
bool b2 = is_different<int,int>::value; // <--- error
std::cout << std::boolalpha << b1 << 'n'
<< b2 << 'n';
return 0;
}
错误:
main.cpp: In instantiation of ‘struct base<int, int>’:
main.cpp:25:17: required by substitution of ‘template<class T, class K> static char (& is_different<U, V>::test(is_different<U, V>::checker<T, K>*))[1] [with T = T; K = K; U = int; V = int] [with T = int; K = int]’
main.cpp:31:41: required from ‘const bool is_different<int, int>::value’
main.cpp:39:38: required from here
main.cpp:7:36: error: duplicate base type ‘id<int>’ invalid
template< class U, class V> struct base: public id<U>, public id<V>
为什么我不能将重复继承的失败用作 SFINAE?
SFINAE 仅适用于直接在函数签名中的事物。你得到的编译错误发生在base<T, K>
的实例化中,这是从函数签名中删除的两个步骤。
也就是说,你为什么要这样做?
template <typename T, typename U>
struct is_same { static const bool value = false; };
template <typename T>
struct is_same<T, T> { static const bool value = true; };
template <typename T, typename U>
struct is_different { static const bool value = !is_same<T, U>::value; };
编辑:
因此,为了回答您在评论中的问题,让我解释更多关于 SFINAE 的信息。该标准在 17.8.2p8 中指定了 SFINAE:
如果替换导致类型或表达式无效,则类型推断将失败。无效的类型或 rexpression 是使用替换参数编写时格式不正确的类型或表达式。只有函数类型及其模板参数类型的直接上下文中的无效类型和表达式才可能导致推导失败。[注意:对替换类型和表达式的计算可能会导致副作用,例如类模板专用化和/或函数模板专用化的实例化、隐式定义函数的生成等。这种副作用不在"直接上下文"中,可能导致程序格式不正确。- 尾注]
这里的问题在于"直接上下文"。您在这里正在做两件事,从直接上下文中删除您的错误。
- 在计算
checker
的默认参数表达式时发生错误。尽管此评估是由test
的参数列表中出现checker<T,K>
触发的,该参数列表被实例化以解决重载,但它不是直接上下文。您可以通过将base
的定义更改为template <typename T, typename U> struct base {};
来尝试此操作。这使得base
实例化中的错误消失,将其替换为默认参数表达式上下文中的错误("没有名为value
的成员")。但SFINAE仍然不会触发;您仍然会收到一个硬错误。 - 错误发生在
base
定义的实例化中。这是从过载解决中移除的又一步。出于同样的原因,将成员放入具有类型T::foobar
的base
中对于找出T
是否包含类型foobar
不起作用:base
的定义不再是SFINAE上下文。通过从图片中删除checker
,您可以看到这本身就是一个错误,例如这样做:
template <typename U, typename V> struct base: public id<U>, public id<V> {
typedef void type;
};
template <typename U, typename V> struct is_different {
struct true_ { char c[1]; }; // I don't like sizeof(reference type),
struct false_ { char c[2]; }; // makes me nervous.
template <typename T, typename K>
static true_ test(typename base<T, K>::type*);
template <typename, typename>
static false_ test(...);
static const bool value = sizeof(test<U, V>(0)) == sizeof(true_);
};
现在,base
实例化不会隐藏在模板默认参数表达式后面,而是在签名中,但您仍然会收到错误。
相关文章:
- VS2017 上 SFINAE 的编译错误
- 进行 SFINAE 练习时编译错误
- 尝试编译SFINAE检查中使用的方法体时发生编译错误
- C++ 带有 decltype 的 SFINAE:替换失败成为错误?
- 使用模板时可能是编译器中的 SFINAE 错误?
- 尝试使用具有尾随返回类型的 lambda 进行 SFINAE 时出现硬错误
- 如何对 SFINAE 进行"deep",即当替换导致代码中进一步出现一些编译错误时?
- 尾随返回类型中带有 SFINAE 的 GCC 错误
- 防止编码器错误 - 忘记在"std::enable_if<>::type"中添加"::type" (SFINAE)
- 为什么这个 SFINAE 在 gcc 中给出错误
- 在模板 SFINAE 约束中使用间接寻址级别会导致硬错误
- 使用C ,使用SFINAE测试静态成员的存在,返回错误的值
- 将 SFINAE 上下文中不正确的模板实例化的硬错误转变为软错误
- 在VS2015编译中键入Sfinae,但会产生错误
- VC++ SFINAE 给出错误 C2070:"重载函数":操作数大小非法
- 从MSVC2015更新2移植到GCC 5.3-SFINAE错误
- C++模板sfinae错误
- 模板实例化上的SFINAE错误
- 使用 SFINAE 但不创建编译错误
- VS2013 上的 SFINAE 错误