語境
我正在撰寫一個帶有三個引數的類模板,以便它可以復制/移動構造,復制/移動可分配。該類有兩個模板引數:(1) 命名型別tree_t和 (2) 列舉值
enum class bounding_t { bound, unbound };
如果 (2) 是,bounding_t::bound那么該類需要有一個成員const tree_t&;當 (2) 是bounding_t::unbound時,該類不應該有它。為此,我使用了條件繼承:
template <typename tree_t, bounding_t bound>
using base_impl =
std::conditional_t<is_collection_bound<bound>,
base_tree<tree_t>,
base<tree_t>>;
template <typename tree_t, bounding_t bound>
class arrangement_collection : public base_impl<tree_t, bound> { }
建構式用于std::enable_if_t適當地構造父類。
嘗試解決
我嘗試了幾件事來使類復制/移動可分配和復制/移動可構造(我不確定我是否可以在不超過正文大小限制的情況下列出所有這些),但我沒有做到,因此沒有一個斷言失敗,并且編譯器不會發出任何警告。下面的 MWE 使四個斷言失敗,都涉及bounding_t::bound. 使這四個斷言不失敗的唯一代碼更改是沒有模板引數的復制賦值運算子的定義(operator=下面的 MWE 中 this 的定義具有模板引數)。
arrangement_collection& operator= (const arrangement_collection& ac) noexcept
{
m_num_nodes = ac.m_num_nodes;
return *this;
}
但是,如果沒有模板引數,我會收到以下我不理解的警告:
warning: implicitly-declared ‘constexpr arrangement_collection<free_tree, bounding_t::bound>::arrangement_collection(const arrangement_collection<free_tree, bounding_t::bound>&)’ is deprecated [-Wdeprecated-copy]
../untitled2/main.cpp: In function ‘arrangement_collection<free_tree, bounding_t::bound> proxy_copy()’:
../untitled2/main.cpp:232:29: warning: implicitly-declared ‘constexpr arrangement_collection<free_tree, bounding_t::bound>::arrangement_collection(const arrangement_collection<free_tree, bounding_t::bound>&)’ is deprecated [-Wdeprecated-copy]
232 | const auto ac2 = ac.first;
| ^~~~~
../untitled2/main.cpp:122:33: note: because ‘arrangement_collection<free_tree, bounding_t::bound>’ has user-provided ‘arrangement_collection<tree_t, bound>& arrangement_collection<tree_t, bound>::operator=(const arrangement_collection<tree_t, bound>&) [with tree_t = free_tree; bounding_t bound = bounding_t::bound]’
122 | arrangement_collection& operator= (const arrangement_collection& ac) noexcept
| ^~~~~~~~
我正在使用g (Ubuntu 11.1.0-1ubuntu1~20.04) 11.1.0和警告標志-Wall -W。
問題
如何定義此類模板的復制/移動建構式/賦值運算子,以便所有斷言成功而沒有警告?
最小的作業示例
下面的代碼包含類定義,最后有一些斷言(std::is_constructible_v<>以及許多其他斷言),以及一個main()說明用例的小程序。
#include <type_traits>
#include <cinttypes>
#include <utility>
// -----------------------------------------------------------------------------
struct free_tree {
uint64_t get_num_nodes() const noexcept { return 10; }
free_tree() noexcept = default;
free_tree(uint64_t) noexcept { }
free_tree(const free_tree&) noexcept = default;
free_tree(free_tree&&) noexcept = default;
free_tree& operator= (const free_tree&) noexcept = default;
free_tree& operator= (free_tree&&) noexcept = default;
};
struct rooted_tree {
uint64_t get_num_nodes() const noexcept { return 10; }
rooted_tree() noexcept = default;
rooted_tree(uint64_t) noexcept { }
rooted_tree(const rooted_tree&) noexcept = default;
rooted_tree(rooted_tree&&) noexcept = default;
rooted_tree& operator= (const rooted_tree&) noexcept = default;
rooted_tree& operator= (rooted_tree&&) noexcept = default;
};
enum class bounding_t { bound, unbound };
template<bounding_t b>
static constexpr bool is_collection_bound = b == bounding_t::bound;
template<bounding_t b>
static constexpr bool is_collection_unbound = b == bounding_t::unbound;
// -----------------------------------------------------------------------------
template <typename tree_t>
struct base_tree {
base_tree(const tree_t& t) noexcept : m_t(t) { }
~base_tree() noexcept = default;
base_tree(const base_tree& bt) noexcept = default;
base_tree(base_tree&& bt) noexcept = default;
base_tree& operator= (const base_tree& bt) noexcept = default;
base_tree& operator= (base_tree&& bt) noexcept = default;
const tree_t& m_t;
};
template <typename tree_t>
struct base_empty {
base_empty() noexcept = default;
~base_empty() noexcept = default;
base_empty(const base_empty& bt) noexcept = default;
base_empty(base_empty&& bt) noexcept = default;
base_empty& operator= (const base_empty& bt) noexcept = default;
base_empty& operator= (base_empty&& bt) noexcept = default;
};
template <typename tree_t, bounding_t bound>
using base_impl =
std::conditional_t<is_collection_bound<bound>,
base_tree<tree_t>,
base_empty<tree_t>>;
template <typename tree_t, bounding_t bound>
class arrangement_collection : public base_impl<tree_t, bound> {
public:
template <typename t, bounding_t b> using ac = arrangement_collection<t, b>;
public:
// ------------------
// BASIC CONSTRUCTORS
// when bound == bounding_t::bound
template <bounding_t cb = bound, std::enable_if_t<is_collection_bound<cb>, bool> = true>
arrangement_collection(const tree_t& t) noexcept
: base_tree<tree_t>(t), m_num_nodes(t.get_num_nodes())
{ }
// when bound == bounding_t::unbound
template <bounding_t cb = bound, std::enable_if_t<is_collection_unbound<cb>, bool> = true>
arrangement_collection(uint64_t n) noexcept
: base_empty<tree_t>(), m_num_nodes(n)
{ }
// -----------------
// COPY CONSTRUCTORS
// for bound == bounding_t::bound
template <
typename otree_t,
bounding_t cb = bound, std::enable_if_t<is_collection_bound<cb>, bool> = true
>
arrangement_collection(const arrangement_collection<otree_t, bounding_t::bound>& ac) noexcept
: base_tree<tree_t>(ac.m_t), m_num_nodes(ac.m_num_nodes)
{ }
template <
typename otree_t,
bounding_t cb = bound, std::enable_if_t<is_collection_bound<cb>, bool> = true
>
arrangement_collection(const tree_t& t, const arrangement_collection<otree_t, bounding_t::unbound>& ac) noexcept
: base_tree<tree_t>(t), m_num_nodes(ac.m_num_nodes)
{ }
// for bound == bounding_t::unbound
template <
typename otree_t, bounding_t b,
bounding_t cb = bound, std::enable_if_t<is_collection_unbound<cb>, bool> = true
>
arrangement_collection(const arrangement_collection<otree_t, b>& ac) noexcept
: base_empty<tree_t>(), m_num_nodes(ac.m_num_nodes)
{ }
// -------------------------
// COPY ASSIGNMENT OPERATORS
arrangement_collection& operator= (const arrangement_collection& ac) noexcept
{
m_num_nodes = ac.m_num_nodes;
return *this;
}
void set_num_nodes(uint64_t n) noexcept { m_num_nodes = n; }
public:
uint64_t m_num_nodes;
};
namespace static_assertions {
typedef arrangement_collection<free_tree, bounding_t::bound> ac_free_linear_bound;
typedef arrangement_collection<free_tree, bounding_t::unbound> ac_free_linear_unbound;
typedef arrangement_collection<rooted_tree, bounding_t::bound> ac_rooted_linear_bound;
typedef arrangement_collection<rooted_tree, bounding_t::unbound> ac_rooted_linear_unbound;
static_assert(
std::is_constructible_v<ac_free_linear_bound, const free_tree&>
and not std::is_constructible_v<ac_rooted_linear_bound, const free_tree&>
and std::is_constructible_v<ac_rooted_linear_bound, const rooted_tree&>
//
and std::is_constructible_v<ac_free_linear_bound, free_tree>
and not std::is_constructible_v<ac_rooted_linear_bound, free_tree>
and std::is_constructible_v<ac_rooted_linear_bound, rooted_tree>
//
and std::is_constructible_v<ac_free_linear_bound, const free_tree>
and not std::is_constructible_v<ac_rooted_linear_bound, const free_tree>
and std::is_constructible_v<ac_rooted_linear_bound, const rooted_tree>
//
and std::is_constructible_v<ac_free_linear_bound, free_tree&>
and not std::is_constructible_v<ac_rooted_linear_bound, free_tree&>
and std::is_constructible_v<ac_rooted_linear_bound, rooted_tree&>
//
// These classes *can* be constructed from uint64_t since free_tree is
// constructible from uint64_t
and std::is_constructible_v<ac_free_linear_bound, uint64_t&>
and std::is_constructible_v<ac_rooted_linear_bound, uint64_t&>
and std::is_constructible_v<ac_free_linear_bound, uint64_t>
and std::is_constructible_v<ac_rooted_linear_bound, uint64_t>
);
static_assert(
not std::is_constructible_v<ac_free_linear_unbound, const free_tree&>
and not std::is_constructible_v<ac_free_linear_unbound, const rooted_tree&>
and not std::is_constructible_v<ac_rooted_linear_unbound, const free_tree&>
and not std::is_constructible_v<ac_rooted_linear_unbound, const rooted_tree&>
and std::is_constructible_v<ac_free_linear_unbound, uint64_t>
and std::is_constructible_v<ac_rooted_linear_unbound, uint64_t>
);
static_assert(
std::is_copy_constructible_v<ac_free_linear_bound>
and std::is_copy_constructible_v<ac_free_linear_unbound>
and std::is_copy_constructible_v<ac_rooted_linear_bound>
and std::is_copy_constructible_v<ac_rooted_linear_unbound>
);
static_assert(std::is_copy_assignable_v<ac_free_linear_bound>);
static_assert(std::is_copy_assignable_v<ac_rooted_linear_bound>);
static_assert(
std::is_copy_assignable_v<ac_free_linear_unbound>
and std::is_copy_assignable_v<ac_rooted_linear_unbound>
);
static_assert(
std::is_move_constructible_v<ac_free_linear_bound>
and std::is_move_constructible_v<ac_free_linear_unbound>
and std::is_move_constructible_v<ac_rooted_linear_bound>
and std::is_move_constructible_v<ac_rooted_linear_unbound>
);
static_assert(
std::is_move_constructible_v<ac_free_linear_bound>
and std::is_move_constructible_v<ac_free_linear_unbound>
and std::is_move_constructible_v<ac_rooted_linear_bound>
and std::is_move_constructible_v<ac_rooted_linear_unbound>
);
static_assert(
std::is_move_assignable_v<ac_free_linear_unbound>
and std::is_move_assignable_v<ac_rooted_linear_unbound>
);
static_assert(std::is_move_assignable_v<ac_free_linear_bound>);
static_assert(std::is_move_assignable_v<ac_rooted_linear_bound>);
} // -- namespace static_assertions
std::pair<
arrangement_collection<free_tree,bounding_t::bound>,
arrangement_collection<free_tree,bounding_t::unbound>
>
make_arrangement_collection() noexcept
{
free_tree ft;
arrangement_collection<free_tree,bounding_t::bound> acb(ft);
acb.set_num_nodes(10);
arrangement_collection<free_tree,bounding_t::unbound> acu(10);
acu.set_num_nodes(10);
return std::make_pair(std::move(acb), std::move(acu));
}
arrangement_collection<free_tree,bounding_t::bound>
proxy_copy() noexcept
{
const auto ac = make_arrangement_collection();
const auto ac2 = ac.first;
return ac2;
}
arrangement_collection<free_tree,bounding_t::bound>
proxy_move() noexcept
{
const auto ac = make_arrangement_collection();
return std::move(ac.first);
}
int main() {
const auto accopy = proxy_copy();
const auto acmove = proxy_move();
}
對“最小”的評論
原始類模板具有三個模板引數和兩倍的代碼行數。
提供的整個代碼很長,因為它包含一個main()程序的定義、兩個類和斷言,但實際的類模板很小。
uj5u.com熱心網友回復:
您的類目前沒有復制建構式,因為復制建構式不能是模板(并且您定義的模板永遠不會被使用)。對于具有用戶定義的復制賦值運算子的型別,不推薦生成隱式定義的復制建構式。
但是,復制建構式的默認定義可以滿足您的需求(復制 abase_empty<tree_t>沒有開銷),因此arrangement_collection(const arrangement_collection&) = default;可以正常作業。
您也可以重寫它,使建構式位于base_tree<tree_t>andbase_empty<tree_t>中,因此arrangement_collection您可以只繼承建構式 with using base_impl<tree_t, bound>::base_impl,避免所有enable_ifSFINAE
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/459552.html
上一篇:Woocommerce-根據訂單中的產品數量更改CSS類
下一篇:在C 中初始化模板類私有靜態變數
