因为struct A
不支持--
运算符,所以下面的代码无法编译。
struct A {};
struct B {
void Run() {}
A& Dec(A& a) { return --a; }
};
int main(int argc, char** argv) {
B b;
b.Run();
}
这段代码也是如此。
struct A {};
template <class T>
struct B {
void Run() {}
A& Dec(A& a) { return --a; }
};
int main(int argc, char** argv) {
B<A> b;
b.Run();
}
那么为什么要编译(在C++11中)呢?
struct A {};
template <class T>
struct B {
void Run() {}
T& Dec(T& a) { return --a; }
};
int main(int argc, char** argv) {
B<A> b;
b.Run();
}
看起来,实例化模板并不会自动实例化模板中依赖于类型检查的类型参数的未使用的方法,这意味着即使它的一些方法不匹配,模板也会匹配。这很令人失望,因为我希望使用SFINAE来检测各种方法和运算符对类型的适用性,但是如果模板替换成功,即使对方法的调用是编译时错误,该技术也不会起作用。
发布于 2017-07-18 01:34:11
(由C++委员会决定)模板类的方法只有在使用时才会实例化它们的主体。
这使得编写一些C++代码变得更容易,但代价是在使用它们时会出现硬错误。
例如,std::vector
将其与std::vector::operator<
一起使用;如果没有<
调用它,则是错误的。如果你这样做了,调用它是可行的。
更现代的C++会鼓励禁用它,这样您就可以检测<
是否安全,但是在设计std::vector
时并没有使用这种技术。您可以看到这种技术在std::function
中的使用的演变,从贪婪地使用通用构造函数中的几乎任何东西到只有在C++11和C++14之间工作时才考虑重载解析的构造函数。
如果你想要SFINAE,你就不能像那样依赖代码体。为了减轻编译器的负载,在进行SFINAE测试时,编译器只需检查声明而不是函数的定义。
部分原因是SFINAE在表情上很难;在整个身体上更难。编译器必须推测性地编译函数体,命中错误,然后返回到“不,什么都没做”状态。
函数体中的错误总是硬错误。在当前版本的C++中,这是无法避免的。
现在,您可以编写函数来决定是否会有错误,但实际上没有错误,然后使用它们的主体来确定其他代码是否会出错。例如:
template<class T>
auto foo() {
constexpr if(sizeof(T)<4) {
return std::true_type{};
} else {
return std::false_type{};
}
你可以在某个地方使用foo<char>()
,它的true
或false
-ness可以使另一个重载替换失败或不失败。
注意,错误(如果有)仍然发生在函数体之外(这里是foo
)。
https://stackoverflow.com/questions/45150007
复制相似问题