簡體   English   中英

C++ 模板接受 const 和 non-const 對象

[英]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_tstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM