[英]C++ template to accept both const and non-const objects
如何獲得以下代碼進行編譯? 我想支持提供給構造函數的 c 樣式數組和 std::array 的所有 constness 變體。
#include <cstddef>
#include <array>
template <typename T>
class Base
{
public:
explicit Base(T* data) : data_(data) {}
private:
T* data_;
};
template <typename T, std::size_t S>
class A : public Base<T>
{
public:
explicit A(T (&array)[S]) : Base<T>(array) { ; }
template <template <typename, std::size_t> class C>
explicit A(C<T, S>& c) : Base<T>(c.begin())
{
;
}
template <template <typename, std::size_t> class C>
explicit A(C<T, S> const& c) : Base<T>(c.begin())
{
;
}
};
int main()
{
constexpr std::size_t size{5U};
int c_style_array[size] = {2, 6, 7, 8, 3};
A<int, size> a(c_style_array); // OK
int const c_style_array_const[size] = {2, 6, 7, 8, 3};
A<int const, size> b(c_style_array_const); // OK
std::array<int, size> std_array = {2, 6, 7, 8, 3};
A<int, size> c(std_array); // OK
std::array<int const, size> std_array_const_1 = {2, 6, 7, 8, 3};
A<int const, size> d(std_array_const_1); // OK
std::array<int const, size> const std_array_const_2 = {2, 6, 7, 8, 3};
A<int const, size> e(std_array_const_2); // OK
std::array<int, size> const std_array_const_3 = {2, 6, 7, 8, 3};
A<int, size> f(std_array_const_3); // NOT OK
}
錯誤信息:
*a.cpp: In instantiation of ‘A<T, S>::A(const C<T, S>&) [with C = std::array; T = int; long unsigned int S = 5]’:
a.cpp:46:37: required from here
a.cpp:26:53: error: invalid conversion from ‘std::array<int, 5>::const_iterator {aka const int*}’ to ‘int*’ [-fpermissive]
explicit A(C<T, S> const& c) : Base<T>(c.begin())
^
a.cpp:7:14: note: initializing argument 1 of ‘Base<T>::Base(T*) [with T = int]’
explicit Base(T* data) : data_(data) {}*
以下聲明
std::array<int, size> const std_array_const_3 = {2, 6, 7, 8, 3};
A<int, size> f(std_array_const_3); // NOT OK
不起作用,因為A<int, size>
從包含int *
的Base<int>
> 繼承,並且您嘗試使用std_array_const_3.begin()
對其進行初始化,該迭代器返回您可以粗略地視為int const *
的 const 迭代器。
而且,顯然,您不能用int const *
初始化int *
* 。
在我看來, f
應該是A<int const, size>
,而不是A<int, size>
。 不幸的是A<int const, size>
不能從std::array<int, size> const
初始化。
所以我建議在A
中添加以下構造函數來管理這種特殊情況
template <template <typename, std::size_t> class C,
typename U = typename std::remove_const<T>::type>
explicit A(C<U, S> const & c) : Base<T>(c.begin())
{ }
此解決方案使用std::remove_const
,從 C++11 開始可用,但我想您可以輕松地在 C++98/C++03 中創建一個替代品。
另一種方法是修改C<T, S> const &
構造函數以匹配兩種情況,如下所示
template <typename U, template <typename, std::size_t> class C,
std::enable_if_t<std::is_same_v<U const, T const>, bool> = true>
explicit A(C<U, S> const & c) : Base<T>(c.begin())
{ }
同樣對於std::enable_if_t
和std::is_same_v
,我想您應該能夠構造 C++98/C++03 替代方案。
我想出了一個可行的解決方案,因為它可以控制用於實例化基礎 class 的類型:
#include <cstddef>
#include <array>
template <typename T>
class Base
{
public:
explicit Base(T* data) : data_(data) {}
private:
T* data_;
};
template <typename U, std::size_t S>
class A : public Base<U>
{
public:
template<typename T>
explicit A(T (&array)[S]) : Base<T>(array) { ; }
template <typename T, template <typename, std::size_t> class C>
explicit A(C<T, S>& c) : Base<T>(c.begin())
{
;
}
template <typename T, template <typename, std::size_t> class C>
explicit A(C<T, S> const& c) : Base<T const>(c.begin())
{
;
}
};
int main()
{
constexpr std::size_t size{5U};
int c_style_array[size] = {2, 6, 7, 8, 3};
A<int, size> a(c_style_array); // OK
int const c_style_array_const[size] = {2, 6, 7, 8, 3};
A<int const, size> b(c_style_array_const); // OK
std::array<int, size> std_array = {2, 6, 7, 8, 3};
A<int, size> c(std_array); // OK
std::array<int const, size> std_array_const_1 = {2, 6, 7, 8, 3};
A<int const, size> d(std_array_const_1); // OK
std::array<int const, size> const std_array_const_2 = {2, 6, 7, 8, 3};
A<int const, size> e(std_array_const_2); // OK
std::array<int, size> const std_array_const_3 = {2, 6, 7, 8, 3};
A<int const, size> f(std_array_const_3); // OK
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.