我注意到 MSVC 有时无法推导出其他编译器接受的非类型参数,最近遇到了一个涉及函数 noexcept 说明符的简单示例(自 C++17 以来,它是函数签名的一部分):
template <typename T> struct is_nocv_method : public std::false_type { };
template <typename ReturnT, typename ClassT, bool IsNoexcept, typename... Args>
struct is_nocv_method<ReturnT (ClassT::*)(Args...) noexcept(IsNoexcept)> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)
Godbolt 建议 gcc 12.1 和 clang 14.0 毫无问题地接受这一点,但 MSVC 14.31 (cl.exe 19.31) 无法编译,声称IsNoexcept无法推断。这是编译器缺陷吗?
在实现非投掷交换习语时,我应该使用throw()吗?
namespace A
{
struct B
{
void swap( B& other ) throw()
{ /* fancy stuff that doesn't throw */ }
};
void swap( B& lhs, B& rhs ) throw()
{ lhs.swap(rhs); }
}
namespace std
{
template<>
void swap( A::B& lhs, A::B& rhs ) throw()
{ lhs.swap(rhs); }
}
Run Code Online (Sandbox Code Playgroud)
特别是我担心将throw()规范放在专业化上std::swap.
额外问题:
使用C++ 0x的noexcept关键字时,答案是否有所不同?
在C++ 11中,我的理解是默认情况下析构函数是隐式的noexcept(true),除了:
如果我有一个C明确标记了析构函数的类noexcept(false)(可能是因为它因某些奇怪的原因而抛出,我知道你不应该这样做,以及为什么)那么派生自C或包含类型成员的任何类的析构函数C也成了noexcept(false).
然而,其中包含了一个类std::shared_ptr<C>显然并不自动拥有它的析构函数切换到noexcept(false),并且同样适用于含有std::weak_ptr<C>,std::unique_ptr<C>等等.
这是一个完整的例子:
#include <type_traits>
#include <memory>
struct Normal {
~Normal() {
}
};
struct ThrowsInDtor {
~ThrowsInDtor() noexcept(false) {
throw 42;
}
};
template<typename T>
struct Wrapper {
T t;
};
template<typename T>
struct UniquePtrWrapper {
std::unique_ptr<T> t;
};
template<typename T>
struct SharedPtrWrapper {
std::shared_ptr<T> t;
};
static_assert(std::is_nothrow_destructible<Normal>::value, "A"); // OK
static_assert(!std::is_nothrow_destructible<ThrowsInDtor>::value, "B"); // OK
static_assert(std::is_nothrow_destructible<Wrapper<Normal>>::value, "C"); …Run Code Online (Sandbox Code Playgroud) 我在尝试保持原子time_point时遇到了这个问题,请参阅(原子需要noexcept默认构造函数,如果默认构造函数可用):http://cplusplus.github.io/LWG/lwg-active.html#2165
简单的问题是std :: atomic或类似的将无法在当前std下编译.
考虑到std :: chrono :: clock_type :: now()s是noexcept.似乎奇怪的是,时间点本身并非如此.
我知道标记为的构造函数将尽可能=default"尝试" noexcept.但是,如果我在类之外定义它,它就noexcept不再存在了,正如您可以从此代码中看到的那样:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar
{
Bar() = default;
Bar(Bar&&) = default; // noexcept
};
struct Foo
{
Foo() = default;
Foo(Foo&&);
};
// moving the definition outside makes it noexcept(false)
Foo::Foo(Foo&&) = default; // not noexcept anymore
int main()
{
Foo foo;
Bar bar;
std::cout << std::boolalpha;
// checks
std::cout << std::is_nothrow_move_constructible<Bar>::value << std::endl;
std::cout << std::is_nothrow_move_constructible<Foo>::value << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
如何=default在类外部定义这样的构造函数并制作它noexcept?为什么这样的构造函数noexcept(false)在类外定义?通过智能指针实现 …
std::swap 以这种方式声明:
template <class T> void swap (T& a, T& b)
noexcept (is_nothrow_move_constructible<T>::value &&
is_nothrow_move_assignable<T>::value);
Run Code Online (Sandbox Code Playgroud)
如果我在我的程序中禁用异常(比如使用-fno-exceptionsfor g ++)std::swap,如果它们是移动启用的,那么无论它们是否为noexcept,我都会使用自定义类型的移动操作?
编辑:后续问题:
在意识到std :: swap将始终使用移动时,如果我的类型有它们,我真正的问题是会发生什么样的特征is_nothrow_move_assignable<>?
将std::vector重新分配的时候,如果我的类型始终使用移动noexcept(true)的移动操作?
C++ 14标准定义了find()成员函数,std::map如下所示:
iterator find(const key_type& x);
const_iterator find(const key_type& x) const;
Run Code Online (Sandbox Code Playgroud)
为什么这些功能没有定义为noexcept?内部可能出错的地方,需要抛出一个异常或产生未定义的行为(除了没有找到一个元素,在这种情况下函数返回一个end迭代器并且无论如何都不需要抛出异常)?
说我有这些声明:
using fp_type = void(*)();
using fp2_type = void(*)() noexcept;
Run Code Online (Sandbox Code Playgroud)
和
void func(){}
fp_type fp(func);
Run Code Online (Sandbox Code Playgroud)
演员fp2_type(fp)表现良好吗?反过来(将noexcept指定的函数指针强制转换为没有noexcept说明符的函数指针)?
在下面的代码中,我认为断言不应该触发,但确实如此.
struct A
{
~A() noexcept(false);
};
A f() noexcept;
int main()
{
static_assert(noexcept(f()), "f must be noexcept");
}
Run Code Online (Sandbox Code Playgroud)
该函数f()显然是noexcept,但noexcept(f())被评估为false.(在gcc和clang中)
我错过了什么或者它是一个错误?
在通用上下文中,我们经常写类似的东西
return_type f(arg_type1 arg1, ...)
noexcept(noexcept(statement_1) && noexcept(statement_2) && ... && noexcept(statement_n))
{
statement_1;
statement_2;
...
statement_n;
}
Run Code Online (Sandbox Code Playgroud)
当a statement_k是return语句时,事情并非如此简单.这是不可能写的noexcept(return expr).相反,我应该理解当我们说return expr并分解成几个时发生的事情noexcept(something).但它似乎非常重要.
我想出了类似下面的算法:
return_type是参考类型,那么当然noexcept(expr)就足够了.return_type不是参考类型,但如果return expr是保证复制省略发生的情况,那么再次noexcept(expr)就足够了.noexcept(expr) && std::is_nothrow_move_constructible<return_type>::value && std::is_nothrow_destructible<return_type>::value.这样对吗?或者有更简单的方法吗?案例1将被归入案例3的特例,但案例2和案例3如何?
c++ ×10
noexcept ×10
c++11 ×4
c++17 ×2
atomic ×1
c++-chrono ×1
copy-elision ×1
destructor ×1
dictionary ×1
g++ ×1
swap ×1
templates ×1