【发布时间】:2021-01-30 15:56:17
【问题描述】:
考虑下面的代码示例,一个简单的模板类包装器,带有基本的重载算术运算符。在此类的operator/ 中,如果检测到除以 0,我使用三元运算符抛出异常,否则,我将返回计算结果。
一些.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 . . .
好的,这很简单,而且有效。
假设我想重构这段代码有两个主要目标:
- 首先,将运算符从类中抽象出来
- 不想抛出异常,而是宁愿在编译时断言。
这个类会变成这样:
一些.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,我仍然会收到非常相似的错误消息。
【问题讨论】:
-
你如何在编译时知道一个操作数是否为0?
-
操作数仅在运行时才知道(例如从用户处给出)。不可能在编译时断言它们。如果你不想抛出异常,你可以返回一个
Varcotaining NaN 或类似的东西。 -
该类是模板化的,它必须推断类型,并且在
main函数内t2被初始化为0。这应该无法编译......我认为static_assert应该能够检测到这一点。这不像我在运行时从控制台或某些文件中获取值。 -
“常数值”通常是指编译时间常数。我认为你想要的是不可能的。您可以使用
consteval,以便您的函数只能在编译时使用。但这可能不是你想要的。 -
抱歉,C++ 不能这样工作。
标签: c++ c++17 assert throw static-assert