问题描述
考虑下面的代码示例,一个带有基本重载算术运算符的简单模板类包装器。在此类的 operator/
中,如果检测到除以 0,我将使用三元运算符抛出异常,否则我将返回计算结果。
some.h
#pragma once
#include <cassert>
#include <stdexcept>
template<typename T>
struct Var {
T var;
// ... other operators
const auto operator/(const Var& rhs) {
return ((rhs.var == 0) ? throw std::exception("Division by 0") : (var / rhs.var));
}
};
这是驱动程序:
#include <iostream>
#include "some.h"
int main() {
try {
Var<int> t1{ 4 };
Var<int> t2{ 0 };
auto t3 = t1 / t2;
std::cout << t3 << '\n';
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
} catch (...) {
std::cerr << "Unknown Exception\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
这将编译和构建,当我们运行它时(我使用的是 Visual Studio),它会抛出一个异常,将此消息发送到控制台
Division by 0
C:\Users\...\source\repos\Data Structure Samples\x64\Debug\Data Structure Samples.exe (process 8756) exited with cod
e 1.
To automatically close the console when debugging stops,enable Tools->Options->Debugging->Automatically close the conso
le when debugging stops.
Press any key to close this window . . .
好的,这很简单,而且有效。
假设我想重构这段代码有两个主要目标:
- 首先,从类中抽象出操作符
- 不想抛出异常,而是在编译时断言。
这个类会变成这样:
some.h
#pragma once
#include <cassert>
#include <stdexcept>
template<typename T>
struct Var {
T var;
};
// ... other operators
template<typename T>
const auto operator/(const Var<T>& lhs,const Var<T>& rhs) {
static_assert(rhs.var != 0,"Division by 0!");
return (lhs.var / rhs.var);
}
但是,由于这些生成的错误而无法编译...
1>------ Build started: Project: Data Structure Samples,Configuration: Debug x64 ------
1>main.cpp
1>c:\users\...\source\repos\data structure samples\data structure samples\datastructs.h(25): error C2131: expression did not evaluate to a constant
1>c:\users\...\source\repos\data structure samples\data structure samples\datastructs.h(25): note: failure was caused by a read of a variable outside its lifetime
1>c:\users\...\source\repos\data structure samples\data structure samples\datastructs.h(25): note: see usage of 'rhs'
1>c:\users\...\source\repos\data structure samples\data structure samples\main.cpp(15): note: see reference to function template instantiation 'const auto operator /<int>(const Var<int> &,const Var<int> &)' being compiled
1>Done building project "Data Structure Samples.vcxproj" -- FAILED.
========== Build: 0 succeeded,1 failed,0 up-to-date,0 skipped ==========
我可以很容易地在运行时使用 assert
而没有任何问题,但是,我正在努力弄清楚如何在这种情况下正确使用 static_assert
。我做错了什么,我在这里错过了什么?我在网上搜索了 static_assert
的各种用例示例,但没有找到任何合适的。即使我将运算符移回类中并尝试使用 static_assert
,我仍然会收到非常相似的错误消息。
解决方法
经过仔细研究,我找到了一个可行的解决方案。断言或抛出异常都不会导致程序中止。
但是,在以后的计算中使用它时会有一点担心......这将迫使我按照这些术语编写其余的源代码,并且必须检查所有内容以确保它不是{ {1}} 以防止任何进一步的计算在不退出应用程序的情况下提前中止。
话虽如此,这就是我所做的,这就是我的操作员现在的样子......
NaN
当我运行相同的程序时,#include <cmath>
template<typename T>
struct Var {
T var;
};
template<typename T>
const auto operator/(const Var<T>& lhs,const Var<T>& rhs) {
return (rhs.var == 0) ? nan("0") : (lhs.var / rhs.var);
}
会打印到控制台。