[C ++模板同时接受const和非const对象

问题描述 投票:0回答:1

如何获取以下代码进行编译?我想支持提供给构造函数的c样式数组和std :: array的所有常量性变体。

#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) {}*

我更喜欢使用的解决方案,但我也对使用的解决方案感兴趣。

c++ templates const
1个回答
0
投票

以下声明

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>继承自包含Base<int>int *,并且您尝试使用std_array_const_3.begin()对其进行初始化,并返回一个可以大致视为int const *的常量迭代器。

而且,显然,您无法使用int *初始化int const *

在我看来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替代品。

© www.soinside.com 2019 - 2024. All rights reserved.