【问题标题】:Raw pointer implicitly converts to const pointer, need the same with user type原始指针隐式转换为 const 指针,需要与用户类型相同
【发布时间】:2015-09-02 23:50:32
【问题描述】:

如果我有一个模板函数接受指向模板类型的指针:

template<typename T>
void foo(const T* x);

它自然接受指向非 const 对象的指针:

int* x = ...;
foo(x); //int* implicitly converted to const int *

我想对具有指针语义的模板类做同样的事情。

例如,最近提出的array_view 类是一个连续内存块的视图,具有(非拥有)指针语义,可用于引用可变或常量项数组:

array_view<int> av = ...;
av[0] = 1;
array_view<const int> cav = ...;
cav[0] = 1; // <- error: read-only variable is not assignable

问题是上面带有原始指针的模式不起作用:

template<typename T>
void foo(array_view<const T> x);
...
array_view<int> x;
foo(x); // <- error: no matching function for call to 'foo'

即使我添加了在Tconst T 变体之间转换的复制构造函数或转换运算符,编译器也无法解析模板的T

我知道两种解决方法:

  • 在调用时明确指定模板参数:foo&lt;int&gt;(x)
  • 编写一个更通用的模板:template&lt;typename U&gt; void foo(U x),并可能使用元编程约束U

有没有更好的解决方案?

【问题讨论】:

    标签: c++ templates constants implicit-conversion


    【解决方案1】:

    显而易见的解决方案是使用

    template <typename T>
    void foo(std::array_view<T> x);
    

    有趣的是,这适用于两种形式的数组视图:

    int array[] = { 1, 2, 3 };
    foo(array_view<int>(std::begin(array), std::end(array)));
    foo(array_view<int const>(std::begin(array), std::end(array)));
    

    参数的const-ness 由参数的const-ness 隐式强制执行。顺便说一句,如果推断出指针类型,指针参数也是如此:

    template <typename T>
    void bar(T*);
    

    当使用int const* 调用bar() 时,类型T 将推导出为T constconst 版本的主要需求是已经推断出类型但参数应该适合。但是,在这种情况下,std::array_view&lt;...&gt; 转换将同样有效。

    【讨论】:

    • 我仍然会想念const 关键字:它为调用者提供了一个承诺。不过嘿嘿,在foo的第一行引入一个新类型:using C = std::add_const&lt;T&gt;::type。有了这个添加,这个答案似乎是最好的解决方法,所以我接受它。
    • @tamas.kenez:static_assert() 没有多大意义:您可能希望接受带有非const 合格Tarray_view&lt;T&gt;。该实现不会修改任何Ts(当然,除非对于特定的T,任何假定为const 的函数恰好不是const)。如果您觉得需要做出承诺,您可以将实现转发到具有 const 限定的函数,并在转发调用时明确指定参数。
    • 我在第一条评论中提到了static_assert。我也发现它没有用,所以我在你的评论之前编辑了评论。
    猜你喜欢
    • 2019-08-21
    • 2013-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    相关资源
    最近更新 更多