如何使用 C++ 转发引用正确指定 noexcept?
How to properly specify noexcept with a C++ forwarding reference?
举个例子:
#include <iostream>
#include <type_traits>
#include <utility>
struct Bar
{
Bar() = default;
Bar(Bar const&) noexcept(false) = default;
Bar(Bar&&) noexcept(true) = default;
};
struct Baz
{
Baz() = default;
Baz(Baz const&) noexcept(true) = default;
Baz(Baz&&) noexcept(false) = default;
};
template<typename T>
class Foo
{
template<typename U, typename V>
using enable_if_same = std::enable_if<std::is_same<typename std::remove_reference<U>::type, V>::value, U>;
public:
template<typename U>
Foo(typename enable_if_same<U, T>::type&& val) // noexcept( ? )
: _val(std::forward<U>(val))
{
}
protected:
T _val;
};
int main(void)
{
std::cout << "Is the Bar copy constructor noexcept? " << std::is_nothrow_copy_constructible<Bar>::value << "\n";
std::cout << "Is the Bar move constructor noexcept? " << std::is_nothrow_move_constructible<Bar>::value << "\n";
std::cout << "Is the Foo<Bar> copy constructor noexcept? " << std::is_nothrow_copy_constructible<Foo<Bar>>::value << "\n";
std::cout << "Is the Foo<Bar> move constructor noexcept? " << std::is_nothrow_move_constructible<Foo<Bar>>::value << "\n";
std::cout << "\n";
std::cout << "Is the Baz copy constructor noexcept? " << std::is_nothrow_copy_constructible<Baz>::value << "\n";
std::cout << "Is the Baz move constructor noexcept? " << std::is_nothrow_move_constructible<Baz>::value << "\n";
std::cout << "Is the Foo<Baz> copy constructor noexcept? " << std::is_nothrow_copy_constructible<Foo<Baz>>::value << "\n";
std::cout << "Is the Foo<Baz> move constructor noexcept? " << std::is_nothrow_move_constructible<Foo<Baz>>::value << "\n";
return 0;
}
编译并运行以上代码产生预期的输出:
Is the Bar copy constructor noexcept? 0
Is the Bar move constructor noexcept? 1
Is the Foo<Bar> copy constructor noexcept? 0
Is the Foo<Bar> move constructor noexcept? 1
Is the Baz copy constructor noexcept? 1
Is the Baz move constructor noexcept? 0
Is the Foo<Baz> copy constructor noexcept? 1
Is the Foo<Baz> move constructor noexcept? 0
但是,我很想知道是否可以显式指定 Foo(U&&)
构造函数的 noexcept-ness,采用转发引用(即我需要替换什么 ?
with 在上面注释掉的 noexcept 说明符中)?
你可以这样做:
template<typename U, typename =
std::enable_if_t<std::is_same_v<std::remove_reference_t<U>, T>>>
Foo(U&& val) noexcept(noexcept(T(std::forward<U>(val))))
: _val(std::forward<U>(val))
{}
里面的noexcept
是一个noexcept
operator, the outer one is a noexcept
specifier.
我不得不改变 SFINAE 的使用方式,因为在你的构造函数中
template<typename U>
Foo(typename enable_if_same<U, T>::type&& val)
: _val(std::forward<U>(val))
{}
无法推导出类型 U
(即使可以,...::type&&
也不会成为转发引用)。
举个例子:
#include <iostream>
#include <type_traits>
#include <utility>
struct Bar
{
Bar() = default;
Bar(Bar const&) noexcept(false) = default;
Bar(Bar&&) noexcept(true) = default;
};
struct Baz
{
Baz() = default;
Baz(Baz const&) noexcept(true) = default;
Baz(Baz&&) noexcept(false) = default;
};
template<typename T>
class Foo
{
template<typename U, typename V>
using enable_if_same = std::enable_if<std::is_same<typename std::remove_reference<U>::type, V>::value, U>;
public:
template<typename U>
Foo(typename enable_if_same<U, T>::type&& val) // noexcept( ? )
: _val(std::forward<U>(val))
{
}
protected:
T _val;
};
int main(void)
{
std::cout << "Is the Bar copy constructor noexcept? " << std::is_nothrow_copy_constructible<Bar>::value << "\n";
std::cout << "Is the Bar move constructor noexcept? " << std::is_nothrow_move_constructible<Bar>::value << "\n";
std::cout << "Is the Foo<Bar> copy constructor noexcept? " << std::is_nothrow_copy_constructible<Foo<Bar>>::value << "\n";
std::cout << "Is the Foo<Bar> move constructor noexcept? " << std::is_nothrow_move_constructible<Foo<Bar>>::value << "\n";
std::cout << "\n";
std::cout << "Is the Baz copy constructor noexcept? " << std::is_nothrow_copy_constructible<Baz>::value << "\n";
std::cout << "Is the Baz move constructor noexcept? " << std::is_nothrow_move_constructible<Baz>::value << "\n";
std::cout << "Is the Foo<Baz> copy constructor noexcept? " << std::is_nothrow_copy_constructible<Foo<Baz>>::value << "\n";
std::cout << "Is the Foo<Baz> move constructor noexcept? " << std::is_nothrow_move_constructible<Foo<Baz>>::value << "\n";
return 0;
}
编译并运行以上代码产生预期的输出:
Is the Bar copy constructor noexcept? 0
Is the Bar move constructor noexcept? 1
Is the Foo<Bar> copy constructor noexcept? 0
Is the Foo<Bar> move constructor noexcept? 1
Is the Baz copy constructor noexcept? 1
Is the Baz move constructor noexcept? 0
Is the Foo<Baz> copy constructor noexcept? 1
Is the Foo<Baz> move constructor noexcept? 0
但是,我很想知道是否可以显式指定 Foo(U&&)
构造函数的 noexcept-ness,采用转发引用(即我需要替换什么 ?
with 在上面注释掉的 noexcept 说明符中)?
你可以这样做:
template<typename U, typename =
std::enable_if_t<std::is_same_v<std::remove_reference_t<U>, T>>>
Foo(U&& val) noexcept(noexcept(T(std::forward<U>(val))))
: _val(std::forward<U>(val))
{}
里面的noexcept
是一个noexcept
operator, the outer one is a noexcept
specifier.
我不得不改变 SFINAE 的使用方式,因为在你的构造函数中
template<typename U>
Foo(typename enable_if_same<U, T>::type&& val)
: _val(std::forward<U>(val))
{}
无法推导出类型 U
(即使可以,...::type&&
也不会成为转发引用)。